1. Genomic scan methods

The aim of this chapter is to make an approach into positive selection among lynxes species through genomic scan methods. After an exhaustive revision of the state of art, we decided to focus on two footprints of positive selection across genome:

  1. Extended Haplotype Homozigosity

  2. Haplotype Frequency Spectrum Distortion

1.1 Data set-up

Once I have filtered, phased and polarized data (see variant_filtering.md , phasing.md or polarization.md), I can start with selection analyses. For this step I am going to use both phased and non-phased vcfs (phased with iHS analyses and non-phased with saltiLASSI). Those files are:

${sp}_goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf

${sp}_goodsamples_filtered_polarized_variants_header_cat_ref.vcf

Moreover, after phasing, allele count is not recalculated so that I used the following code for updating INFO field.

species=(lc ll lp lr)

for sp in ${species[@]}
do
cat ${sp}_goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf | fill-an-ac | bgzip -c > ${sp}_goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf.gz
done

Both methods of selection need to be run per chr

#Separate per chr sp vcf
species=(lc ll lp lr)

for sp in ${species[@]}
do
  echo "$sp"
  CHR=($(cat $STORE2/reference_genomes/Felis_catus_Ref/Felis_catus.Felis_catus_9.0.dna.toplevel.fa.fai | cut -f 1 | uniq))
  for chr in ${CHR[@]:0:18}
    do
      echo "$chr"
      grep -E "^(#|${chr})" \
      $INPUT_FILE \
      > $OUTPUT_FILE
      echo "Done $chr for $sp vcf"
    done
done

1.1.1. Control check: exploring missingness per sp

Code available in missing_distribution.R and missing_distribution.sh

for sp in ${species[@]}
  do
    echo "$sp"
    vcftools \
    --vcf ${sp}_goodsamples_cat_ref.filter8.vcf \
    --missing-site \
    --out ${sp}_missing_site_rate
  done
  
  bcftools query -f '%CHROM %POS  %REF  %ALT [ %GT]\n' lr_goodsamples_cat_ref.filter8.vcf > lr_genotypes_cat_ref.filter8.vcf

1.2 iHS analyses

For iHS analyses we decided to use the “rehh” package available for R. The entire code is available in ihs_sp.R. To run this in CESGA, I had to create a run_ihs.sh script that specify to run the Rscript.

#!/usr/bin/env Rscript

print ("Starting ihs analysis")

#If run in CESGA, install packages before running the code in sbatch
  #install.packages("vcfR")
  #install.packages("rehh")
  #The downloaded source packages are in ‘/tmp/Rtmp7TLpRA/downloaded_packages’
  library(vcfR)
  library(rehh)

#ENABLE command line arguments
sp <- commandArgs(trailingOnly = TRUE)

#sp<- c("lc", "ll", "lp", "lr") ###if I don't run the entire code
#Create a df object empty
df_total <- data.frame()

#Define chromosome variable
chromosomes <- c("A1", "A2", "A3", "B1", "B2", "B3", "B4", "C1", "C2", "D1", "D2", "D3", "D4", "E1", "E2", "E3", "F1", "F2")

#Define paths
input_path<- "/mnt/lustre/scratch/nlsas/home/csic/bie/llf/selection_scan/chr_files/"
output_path<- "/mnt/lustre/scratch/nlsas/home/csic/bie/llf/selection_scan/iHS/"

#loop to bind each chr_sp_scan df in only one
for (chr in chromosomes)
{
  print("Starting loop")
 
  
  #Read the subsetted vcf    
  print ("Reading vcf")  
  data<- data2haplohh(hap_file=paste0(input_path, chr, "_", sp, "_","goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf"), polarize_vcf= "FALSE", allele_coding="01", chr.name=chr, vcf_reader= "vcfR")
  
  #Scan the genome 
  print ("Scanning vcf")  
  data_frame<- scan_hh(data) 
  write.table(data_frame, file=(paste0(output_path, chr, "_", sp, "_", "scan")))
  print ("Saved scan data frame")
  
  df<- read.csv(paste0(output_path, chr, "_", sp, "_", "scan"), sep=" ")
  df_total<- rbind(df_total,df)
  print("Added one more chr in the total df")
}

#Save the sp_scan
write.table(df_total, file=(paste0(output_path, sp, "_scan")), sep="\t", row.names = FALSE, quote = FALSE)

#Calculate genome-wide iHS values
print ("Calculating ihs") 
wgscan.ihs<- ihh2ihs(df_total, (round((min(df_total$FREQ_A) * 2), 2))) 
write.table(wgscan.ihs$ihs, file=(paste0(output_path, sp, "_ihs_scan")), sep="\t", row.names = FALSE, quote = FALSE)
print ("Saved ihs data frame")

1.2 XP-EHH analyses

As with iHS, I used rehh R package. The entire code is available in xpehh_sp.R. To run this in CESGA, I had to create a run_xpehh.sh script that specify to run the Rscript.

#!/usr/bin/env Rscript

print ("Starting xpehh analysis")

#install.packages("vcfR")
#install.packages("rehh")
library(vcfR)
library(rehh)

#Define paths
path<- "/mnt/lustre/scratch/nlsas/home/csic/bie/llf/selection_scan/iHS/"

#Name variables
species<- c("lc", "ll", "lp", "lr")

#Read per sp scan
  for(sp in species) 
    {
    print(paste("Reading", sp, "scan"))
    scan<- read.csv(paste0(path, sp, "_scan"), sep="\t")
    assign(paste0(sp, "_scan"), scan)
  }

#Calculating XP-EHH
print ("Calculating xpehh") 

lc_ll_xpehh <- ies2xpehh(scan_pop1 = lc_scan, scan_pop2 = ll_scan, popname1 = "LC", popname2 = "LL", p.adjust.method = "fdr")
write.table(lc_ll_xpehh, file=(paste0(path, "lc_ll_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)

lc_lp_xpehh <- ies2xpehh(scan_pop1 = lc_scan, scan_pop2 = lp_scan, popname1 = "LC", popname2 = "LP", p.adjust.method = "fdr")
write.table(lc_lp_xpehh, file=(paste0(path, "lc_lp_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)


lc_lr_xpehh <- ies2xpehh(scan_pop1 = lc_scan, scan_pop2 = lr_scan, popname1 = "LC", popname2 = "LR", p.adjust.method = "fdr")
write.table(lc_lr_xpehh, file=(paste0(path, "lc_lr_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)


ll_lp_xpehh <- ies2xpehh(scan_pop1 = ll_scan, scan_pop2 = lp_scan, popname1 = "LL", popname2 = "LP", p.adjust.method = "fdr")
write.table(ll_lp_xpehh, file=(paste0(path, "ll_lp_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)


ll_lr_xpehh <- ies2xpehh(scan_pop1 = ll_scan, scan_pop2 = lr_scan, popname1 = "LL", popname2 = "LR", p.adjust.method = "fdr")
write.table(ll_lr_xpehh, file=(paste0(path, "ll_lr_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)


lp_lr_xpehh <- ies2xpehh(scan_pop1 = lp_scan, scan_pop2 = lr_scan, popname1 = "LP", popname2 = "LR", p.adjust.method = "fdr")
write.table(lp_lr_xpehh, file=(paste0(path, "lp_lr_xpehh_scan")), sep="\t", row.names = FALSE, quote = FALSE)

1.3. salti-LASSI

Here I am going to use saltiLASSI to analyse selection from haplotype frequency spectrum (HFS). I used windows of 101 SNPS with a 50 slide. The entire code is available in lassi.sh.

species=(lc ll lp lr)

for sp in ${species[@]}
  do
    echo "$sp"
    #make a sp_ind.txt (pop file) needed for lassip
    sed "s/$/\t${sp}/" <(grep "#CHR" $LUSTRE/${sp}_goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf | tr "\t" "\n" | grep ${sp})  > $LUSTRE/selection_scan/${sp}_ind.txt
    sbatch lassi.sh $sp
  done  
  
species=(lc ll lp lr)

for sp in ${species[@]}
  do
  sbatch lassi.sh $sp
  done

2. Results

2.1 Representation of iHS and salti-LASSI results

For graphics we are going to use R. First thing is to run packages needed and set directories.

#install.packages
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.2     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(rehh)
library(RColorBrewer)
library(cowplot)

Attaching package: ‘cowplot’

The following object is masked from ‘package:lubridate’:

    stamp
library(ggpubr)

Attaching package: ‘ggpubr’

The following object is masked from ‘package:cowplot’:

    get_legend
library(grid)
library(ggrepel)

#Set directories
path<- "/Users/lorenalorenzo"
files<- "/files/"
plots<- "/plots/"

#Name the variables
species<- c("lc", "ll", "lp", "lr")

names <- c("lc" = "Lynx canadensis",
            "lr" = "Lynx rufus",
            "ll" = "Lynx lynx",
            "lp" = "Lynx pardinus")

chr <- c( "A1", "A2", "A3", "B1", "B2", "B3", "B4", "C1", "C2", "D1", "D2", "D3", "D4", "E1", "E2", "E3", "F1", "F2", "X")

colors <- c("lc"= "#AB97B7",
            "ll"= "#F2AB5A",
            "lp"="#EB595F",
            "lr"="#71C178")
#print(as.character(names[species]))
#print(as.character(colors[species]))

#set X axis with chr_size dataframe (for plotting)
    axis_set <- read.table(paste0(path, files, "chr_size.txt"), sep="\t", col.names=c("chr", "size")) %>%
                 mutate(center = size/2)
    #Group by chr
    data_axis <- axis_set %>%
                  mutate(size_cum = lag(cumsum(as.numeric(size)), default = 0)) %>%
                  rowwise() %>%
                  mutate(center_cum = sum(center, size_cum))     

In the following code I prepare iHS and saltiLASSI results for representation with cutoffs.


for (sp in species)
{

# iHS results -------------------------------------------------------------
  ihs_scan <- read.table(paste0(path, files, sp , "_ihs_scan"), sep="\t", header= TRUE, col.names = c("chr", "pos", "ihs", "pval"))
  print("Read ihs_scan data")
  
  #Group by chr
  data_cum <- ihs_scan %>% 
    group_by(chr) %>% 
    summarise(max_bp = max(pos)) %>%
    mutate(bp_add = lag(cumsum(max_bp), default = 0)) %>% 
    select(chr, bp_add)
  
  data_ihs <- ihs_scan %>% 
    inner_join(data_cum, by = "chr") %>% 
    mutate(bp_cum = pos + bp_add) %>%
    na.omit() %>%
    mutate(abs_ihs= abs(ihs)) %>% #absolute value score of iHS
    mutate (dataset="|iHS|")  #for facet_grid
  
  axis_set <- data_ihs %>% 
    group_by(chr) %>% 
    summarize(center = mean(bp_cum))
  
  print("Data set")
    
write.table(data_ihs, file=(paste0(path, files, sp, "data_ihs")), sep="\t", row.names = FALSE, quote = FALSE)
  
  #explore ihs distribution (gaussian)
  # pdf(paste0(path, plots, sp,"_distplot.pdf"), width=10, height=5)
  # distribplot(ihs_scan$IHS, xlab= paste(sp, "iHS"), qqplot = TRUE)
  #dev.off()
  
## define outliers ----------------------------------------------------------------
  
  ihs_outliers<- data_ihs %>% filter(abs_ihs >= 4)
  print(length(ihs_outliers$abs_ihs))
  
  write.table(ihs_outliers, file=(paste0(path, files, sp, "_ihs_4outliers")), sep="\t", row.names = FALSE, quote = FALSE)
  print("outliers df saved")
  
  #Save as 0-based bed file
 bed_4 <- ihs_outliers %>% mutate(start= pos - 1) %>% select(c(1,9,2,3,7))
 write.table(bed_4, file=(paste0(path, files, sp, "_ihs_4outliers.bed")), sep="\t", row.names = FALSE, col.names = FALSE, quote = FALSE)

  
# saltiLASSI results -----------------------------------------------------------
  print("Starting plotting LASSI results code")

  #Read data
  lassi_scan<- read.table(paste0(path, files, sp, "_salti.lassip.hap.out"), sep="\t", header=T)
  print(paste("Read data for", sp))
  
  #Group by chr
  data_cum <- lassi_scan %>% 
    group_by(chr) %>% 
    summarise(max_bp = max(pos)) %>%
    mutate(bp_add = lag(cumsum(max_bp), default = 0)) %>% 
    select(chr, bp_add)
  
  data_lassi <- lassi_scan %>% 
    inner_join(data_cum, by = "chr") %>% 
    mutate(bp_cum = pos + bp_add) %>%
    mutate(dataset="saltiLASSI")
  
  axis_set <- data_lassi %>% 
    group_by(chr) %>% 
    summarize(center = mean(bp_cum))
  
  print("Acumulated by chr")
  
  
  #Change the "sp_L" column name to another in order to make it easier to manage
  colnames(data_lassi)[12]<- "statistic"
  
  print("rename sp_L column to statistic")
  
  write.table(data_lassi, file=(paste0(path, files, sp, "data_lassi")), sep="\t", row.names = FALSE, quote = FALSE)
  
  #Explore statistic distribution
    #pdf(paste0(path, plots, sp,"_L_statistic_distplot.pdf"), width=10, height=5)
  
    #print(ggplot(data_lassi, aes(x= statistic)) +
         # geom_freqpoly(binwidth=10) + 
         # ylim(0, 20000) +
        #  labs (title=sp))
  
   #dev.off()
  
    #print("distribution plot saved")
  
## define outliers ---------------------------------------------------------
  #cut-off 95%
  print(paste(sp, round(length(data_lassi$statistic) * 0.05), "top 5% values"))
  cut_95 <- sort(data_lassi$statistic)[round(length(data_lassi$statistic) * 0.95)]
  print(paste(sp, cut_95, "5% cut-off" ))
  
  lassi_outliers_95<- data_lassi %>% filter(statistic >= cut_95)
  write.table(lassi_outliers_95, file=(paste0(path, files, sp, "_lassi_5%outliers")), sep="\t", row.names = FALSE, quote = FALSE)
  print("outliers df saved")
  
  bed_95 <- lassi_outliers_95  %>% select(c(1,2,3,12))
  write.table(bed_95, file=(paste0(path, files, sp, "_lassi_5%outliers.bed")), sep="\t", row.names = FALSE, col.names = FALSE, quote = FALSE)
}  
[1] "Read ihs_scan data"
[1] "Data set"
[1] 2992
[1] "outliers df saved"
[1] "Starting plotting LASSI results code"
[1] "Read data for lc"
[1] "Acumulated by chr"
[1] "rename sp_L column to statistic"
[1] "lc 1424 top 5% values"
[1] "lc 5.76722 5% cut-off"
[1] "outliers df saved"
[1] "Read ihs_scan data"
[1] "Data set"
[1] 693
[1] "outliers df saved"
[1] "Starting plotting LASSI results code"
[1] "Read data for ll"
[1] "Acumulated by chr"
[1] "rename sp_L column to statistic"
[1] "ll 3080 top 5% values"
[1] "ll 23.5728 5% cut-off"
[1] "outliers df saved"
[1] "Read ihs_scan data"
[1] "Data set"
[1] 1625
[1] "outliers df saved"
[1] "Starting plotting LASSI results code"
[1] "Read data for lp"
[1] "Acumulated by chr"
[1] "rename sp_L column to statistic"
[1] "lp 865 top 5% values"
[1] "lp 6.53881 5% cut-off"
[1] "outliers df saved"
[1] "Read ihs_scan data"
[1] "Data set"
[1] 3880
[1] "outliers df saved"
[1] "Starting plotting LASSI results code"
[1] "Read data for lr"
[1] "Acumulated by chr"
[1] "rename sp_L column to statistic"
[1] "lr 8763 top 5% values"
[1] "lr 10.0232 5% cut-off"
[1] "outliers df saved"

2.2 Intersect between methods

Once saved the outliers bed from iHS and saltiLASSI, we need the overlap of both methods. For doing that, here we are using bedtools. Firstly, I merge every overlapping outlier window from lassi. Then, we intersect this windows with the outlier SNPs from iHS to get putative selected genomic REGIONS. Use 5% as cutoff for lassi because after that we are going to rank 10 best regions.

module load bedtools

species=(lc ll lp lr)

for sp in ${species[@]}
  do
    echo "$sp"
       #merge every overlapping outlier window in LASSI 
       bedtools merge \
       -i ${sp}_lassi_5%outliers.bed \
       -c 1 \
       -o count \
       > ${sp}_merged_tmp
       echo "$sp merged"
       
       #intersect with iHS snps so the result are GENOMIC REGIONS under putative selection
       bedtools intersect \
       -a ${sp}_merged_tmp \
       -b ${sp}_ihs_4outliers.bed \
       -c \
       > ${sp}_intersected_tmp
       echo "$sp intersected"
       
       #add snp density        
       bedtools intersect \
       -a ${sp}_intersected_tmp \
       -b $LUSTRE/vcfs/${sp}_goodsamples_filtered_phased_polarized_variants_header_cat_ref.vcf \
       -c \
     > ${sp}_snps_density_tmp
     
       #calculate lassi values for those regions
       bedtools map \
       -a ${sp}_snps_density_tmp\
       -b ${sp}_lassi_5%outliers.bed \
       -F 1 \
       -c 4 \
       -o mean,max,sum \
       > ${sp}_lassi_tmp
       echo "$sp lassi statistics calculated"
       
       #calculate iHS values for those regions
       bedtools map \
       -a ${sp}_lassi_tmp \
       -b ${sp}_ihs_4outliers.bed \
       -F 1 \
       -c 5 \
       -o mean,max,sum \
       > ${sp}_lassi_ihs_tmp
       echo "$sp ihs statistics calculated"
       
       #remove 0's (no SNPS)
       awk -F '\t' '$5 != 0' ${sp}_lassi_ihs_tmp > ${sp}_lassi_ihs_regions_tmp
       echo "$sp regions with 0 snps intersected removed"
       
       #print a header (column names)
       echo -e "chr start end windows snps snps_density lassi_mean lassi_max lassi_sum ihs_mean ihs_max ihs_sum" | cat - ${sp}_lassi_ihs_regions_tmp | tr " " "\t" > ${sp}_lassi_ihs_regions 
       
  ######Cross bed results with annotation file (gff3)    
      #match selected regions with genome annotation
       bedtools intersect \
         -a ${sp}_lassi_ihs_regions_tmp \
         -b $STORE2/reference_genomes/Felis_catus_Ref/Felis_catus.Felis_catus_9.0.97.gff3 \
         -wa -wb \
         > ${sp}_annotated_tmp 
        echo "$sp annotated"
        
      #filter only genes
      awk '$15=="gene"' ${sp}_annotated_tmp > ${sp}_gene_tmp
      echo "$sp gene filtered"
    
    #get only interesting columns
    cut -f-12,16,17,21- ${sp}_gene_tmp | tr ' ' '\t' > ${sp}_filtered_tmp
    
    #ensembl id and gene name as column data
    cut -d';' -f1,2 ${sp}_filtered_tmp | tr ';' '\t'  | awk '{if ($16 ~ /Name=[[:alnum:]]/) $16=$16; else $16="NA"; print $0}' > ${sp}_names_tmp 
    
    #cut extra-info from ens code and gene name columns
    paste <(cut -d" " -f-14 ${sp}_names_tmp) <(cut -d" " -f15 ${sp}_names_tmp | cut -d":" -f2) <(cut -d" " -f16 ${sp}_names_tmp | cut -d"=" -f2) |  tr "\t" " "  >> ${sp}_columns_tmp
    
    #print a header (column names)
    echo -e "chr start end windows snps snps_density lassi_mean lassi_max lassi_sum ihs_mean ihs_max ihs_sum gene_start gene_end ensembl_id gene_name" | cat - ${sp}_columns_tmp > ${sp}_genomic_regions_annotated
      
        #remove temporal files
       rm *tmp
    done

2.3 Representation of the intersection

For representation purposes, I want to merge lassi outliers windows data with intersected outilies regions data.

module load bedtools

species=(lc ll lp lr)

#Merge info about lassi results and the final table of genomics regions under selection
for sp in ${species[@]}
  do
    echo "$sp"
    bedtools intersect \
    -a <(grep -v "chr" saltiLASSI/${sp}_salti.lassip.hap.out | cut -f1,2,3,5,12) \
    -b <(grep -v "chr" ${sp}_5%outliers_table) \
    -wao \
    > ${sp}_results_table_representation
  done  
[1] "lc 1424 top 5% values"
[1] "lc 5.76722 5% cut-off"
[1] "ll 3080 top 5% values"
[1] "ll 23.5728 5% cut-off"
[1] "lp 865 top 5% values"
[1] "lp 6.53881 5% cut-off"
[1] "lr 8763 top 5% values"
[1] "lr 10.0232 5% cut-off"

CLARIFICATION: In the plot we can see * below the cutoff. That’s because another overlapping window passed the cutoff value, so now the region includes windows that by its own didn’t were outliers.

Now I want to explore regions defined in a chr

2.3 Representation of XP-EHH

3. Interpretation

3.1 Looking for enrichment pathways

We tried to find out pathways or functions specifically being under selection pressure among the putative selected regions (those overpassing the filter for both methods). Unfortunately, GO enrichment analyses done in PANTHER results in no enrichment pathway in no species.

3.2 Top regions

As we didn’t get any significant result in the enrichment analyses, we decided to look for the most important regions under selection in each species. For doing so, we had to decided what parameter describes better which regions are “the most important ones”.

From the resulting table I get the top 10 putative regions per sp.

#Read data
for (sp in species)
{
data<- read.table(paste0(path, files, sp, "_lassi_ihs_regions"), sep="\t", header=T)
assign(paste0(sp, "_results"), data )

data_top10<- data %>%
  arrange(desc(lassi_max)) %>%
  slice(1:10)
#write.table(data_top10, file=(paste0(path, files, sp, "_top10")), sep="\t",row.names = FALSE, quote = FALSE)

assign(paste0(sp, "_top10"), data_top10 )
}

In order to explore the distribution of the lassi statistic in each of the 10 top regions, I firstly get the statistic value in every window of the top region and then represent it.

module load bedtools

species=(lc ll lp lr)

for sp in ${species[@]}
  do
    echo "$sp"
    #convert into a bed file
    awk '{printf("%s\t%d\t%d\t%d\t%d\n", $1, $2, $3, $5, $12)}' saltiLASSI/${sp}_salti.lassip.hap.out  > ${sp}_tmp

    #intersect btw lassi values and genomic regions with 100% coincidence (only windows embedded in the genomic regions are reported)
       bedtools intersect -wa -wb \
       -a <(grep -v "chr" ${sp}_tmp) \
       -b <(grep -v "chr" ${sp}_top10 | cut -f1-3) \
       -f 1.0 \
       > ${sp}_lassi_top10  
       echo "$sp intersected"
    
  #remove temporal files
  rm *tmp
  done

Now I want to represent each top10 genomic regions and the correspondent lassi values. Taking into account I previously calculated the genes under the genomic outlier regions, we can add this info to the plot

Warning: Detected an unexpected many-to-many relationship between `x` and `y`.Warning: Removed 16 rows containing missing values (`geom_segment()`).Warning: Removed 12 rows containing missing values (`geom_segment()`).Warning: Removed 8 rows containing missing values (`geom_segment()`).

LS0tCnRpdGxlOiAiUG9zaXRpdmUgc2VsZWN0aW9uIGdlbm9taWMgc2NhbiBvbiBseW54ZXMiCmF1dGhvcjogIkxvcmVuYSBMb3JlbnpvIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lYi0lWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIyAxLiBHZW5vbWljIHNjYW4gbWV0aG9kcwoKVGhlIGFpbSBvZiB0aGlzIGNoYXB0ZXIgaXMgdG8gbWFrZSBhbiBhcHByb2FjaCBpbnRvIHBvc2l0aXZlIHNlbGVjdGlvbiBhbW9uZyBseW54ZXMgc3BlY2llcyB0aHJvdWdoIGdlbm9taWMgc2NhbiBtZXRob2RzLiBBZnRlciBhbiBleGhhdXN0aXZlIHJldmlzaW9uIG9mIHRoZSBzdGF0ZSBvZiBhcnQsIHdlIGRlY2lkZWQgdG8gZm9jdXMgb24gdHdvIGZvb3RwcmludHMgb2YgcG9zaXRpdmUgc2VsZWN0aW9uIGFjcm9zcyBnZW5vbWU6CgoxLiAgRXh0ZW5kZWQgSGFwbG90eXBlIEhvbW96aWdvc2l0eQoKMi4gIEhhcGxvdHlwZSBGcmVxdWVuY3kgU3BlY3RydW0gRGlzdG9ydGlvbgoKIyMjIDEuMSBEYXRhIHNldC11cAoKT25jZSBJIGhhdmUgZmlsdGVyZWQsIHBoYXNlZCBhbmQgcG9sYXJpemVkIGRhdGEgKHNlZSB2YXJpYW50X2ZpbHRlcmluZy5tZCAsIHBoYXNpbmcubWQgb3IgcG9sYXJpemF0aW9uLm1kKSwgSSBjYW4gc3RhcnQgd2l0aCBzZWxlY3Rpb24gYW5hbHlzZXMuIEZvciB0aGlzIHN0ZXAgSSBhbSBnb2luZyB0byB1c2UgYm90aCBwaGFzZWQgYW5kIG5vbi1waGFzZWQgdmNmcyAocGhhc2VkIHdpdGggaUhTIGFuYWx5c2VzIGFuZCBub24tcGhhc2VkIHdpdGggc2FsdGlMQVNTSSkuIFRob3NlIGZpbGVzIGFyZToKCmAke3NwfV9nb29kc2FtcGxlc19maWx0ZXJlZF9waGFzZWRfcG9sYXJpemVkX3ZhcmlhbnRzX2hlYWRlcl9jYXRfcmVmLnZjZmAKCmAke3NwfV9nb29kc2FtcGxlc19maWx0ZXJlZF9wb2xhcml6ZWRfdmFyaWFudHNfaGVhZGVyX2NhdF9yZWYudmNmYAoKTW9yZW92ZXIsIGFmdGVyIHBoYXNpbmcsIGFsbGVsZSBjb3VudCBpcyBub3QgcmVjYWxjdWxhdGVkIHNvIHRoYXQgSSB1c2VkIHRoZSBmb2xsb3dpbmcgY29kZSBmb3IgdXBkYXRpbmcgSU5GTyBmaWVsZC4KCmBgYHtiYXNoIGV2YWw9RkFMU0V9CnNwZWNpZXM9KGxjIGxsIGxwIGxyKQoKZm9yIHNwIGluICR7c3BlY2llc1tAXX0KZG8KY2F0ICR7c3B9X2dvb2RzYW1wbGVzX2ZpbHRlcmVkX3BoYXNlZF9wb2xhcml6ZWRfdmFyaWFudHNfaGVhZGVyX2NhdF9yZWYudmNmIHwgZmlsbC1hbi1hYyB8IGJnemlwIC1jID4gJHtzcH1fZ29vZHNhbXBsZXNfZmlsdGVyZWRfcGhhc2VkX3BvbGFyaXplZF92YXJpYW50c19oZWFkZXJfY2F0X3JlZi52Y2YuZ3oKZG9uZQoKYGBgCgpCb3RoIG1ldGhvZHMgb2Ygc2VsZWN0aW9uIG5lZWQgdG8gYmUgcnVuIHBlciBjaHIKCmBgYHtiYXNoIGV2YWw9RkFMU0V9CgojU2VwYXJhdGUgcGVyIGNociBzcCB2Y2YKc3BlY2llcz0obGMgbGwgbHAgbHIpCgpmb3Igc3AgaW4gJHtzcGVjaWVzW0BdfQpkbwogIGVjaG8gIiRzcCIKICBDSFI9KCQoY2F0ICRTVE9SRTIvcmVmZXJlbmNlX2dlbm9tZXMvRmVsaXNfY2F0dXNfUmVmL0ZlbGlzX2NhdHVzLkZlbGlzX2NhdHVzXzkuMC5kbmEudG9wbGV2ZWwuZmEuZmFpIHwgY3V0IC1mIDEgfCB1bmlxKSkKICBmb3IgY2hyIGluICR7Q0hSW0BdOjA6MTh9CiAgICBkbwogICAgICBlY2hvICIkY2hyIgogICAgICBncmVwIC1FICJeKCN8JHtjaHJ9KSIgXAogICAgICAkSU5QVVRfRklMRSBcCiAgICAgID4gJE9VVFBVVF9GSUxFCiAgICAgIGVjaG8gIkRvbmUgJGNociBmb3IgJHNwIHZjZiIKICAgIGRvbmUKZG9uZQpgYGAKCiMjIyMgMS4xLjEuIENvbnRyb2wgY2hlY2s6IGV4cGxvcmluZyBtaXNzaW5nbmVzcyBwZXIgc3AKCkNvZGUgYXZhaWxhYmxlIGluIG1pc3NpbmdfZGlzdHJpYnV0aW9uLlIgYW5kIG1pc3NpbmdfZGlzdHJpYnV0aW9uLnNoCgpgYGB7YmFzaCBldmFsPUZBTFNFfQoKZm9yIHNwIGluICR7c3BlY2llc1tAXX0KICBkbwogICAgZWNobyAiJHNwIgogICAgdmNmdG9vbHMgXAogICAgLS12Y2YgJHtzcH1fZ29vZHNhbXBsZXNfY2F0X3JlZi5maWx0ZXI4LnZjZiBcCiAgICAtLW1pc3Npbmctc2l0ZSBcCiAgICAtLW91dCAke3NwfV9taXNzaW5nX3NpdGVfcmF0ZQogIGRvbmUKICAKICBiY2Z0b29scyBxdWVyeSAtZiAnJUNIUk9NICVQT1MgICVSRUYgICVBTFQgWyAlR1RdXG4nIGxyX2dvb2RzYW1wbGVzX2NhdF9yZWYuZmlsdGVyOC52Y2YgPiBscl9nZW5vdHlwZXNfY2F0X3JlZi5maWx0ZXI4LnZjZgpgYGAKCiMjIyAxLjIgaUhTIGFuYWx5c2VzCgpGb3IgaUhTIGFuYWx5c2VzIHdlIGRlY2lkZWQgdG8gdXNlIHRoZSAicmVoaCIgcGFja2FnZSBhdmFpbGFibGUgZm9yIFIuIFRoZSBlbnRpcmUgY29kZSBpcyBhdmFpbGFibGUgaW4gaWhzX3NwLlIuIFRvIHJ1biB0aGlzIGluIENFU0dBLCBJIGhhZCB0byBjcmVhdGUgYSBydW5faWhzLnNoIHNjcmlwdCB0aGF0IHNwZWNpZnkgdG8gcnVuIHRoZSBSc2NyaXB0LgoKYGBge3IgZXZhbD1GQUxTRX0KIyEvdXNyL2Jpbi9lbnYgUnNjcmlwdAoKcHJpbnQgKCJTdGFydGluZyBpaHMgYW5hbHlzaXMiKQoKI0lmIHJ1biBpbiBDRVNHQSwgaW5zdGFsbCBwYWNrYWdlcyBiZWZvcmUgcnVubmluZyB0aGUgY29kZSBpbiBzYmF0Y2gKICAjaW5zdGFsbC5wYWNrYWdlcygidmNmUiIpCiAgI2luc3RhbGwucGFja2FnZXMoInJlaGgiKQogICNUaGUgZG93bmxvYWRlZCBzb3VyY2UgcGFja2FnZXMgYXJlIGluIOKAmC90bXAvUnRtcDdUTHBSQS9kb3dubG9hZGVkX3BhY2thZ2Vz4oCZCiAgbGlicmFyeSh2Y2ZSKQogIGxpYnJhcnkocmVoaCkKCiNFTkFCTEUgY29tbWFuZCBsaW5lIGFyZ3VtZW50cwpzcCA8LSBjb21tYW5kQXJncyh0cmFpbGluZ09ubHkgPSBUUlVFKQoKI3NwPC0gYygibGMiLCAibGwiLCAibHAiLCAibHIiKSAjIyNpZiBJIGRvbid0IHJ1biB0aGUgZW50aXJlIGNvZGUKI0NyZWF0ZSBhIGRmIG9iamVjdCBlbXB0eQpkZl90b3RhbCA8LSBkYXRhLmZyYW1lKCkKCiNEZWZpbmUgY2hyb21vc29tZSB2YXJpYWJsZQpjaHJvbW9zb21lcyA8LSBjKCJBMSIsICJBMiIsICJBMyIsICJCMSIsICJCMiIsICJCMyIsICJCNCIsICJDMSIsICJDMiIsICJEMSIsICJEMiIsICJEMyIsICJENCIsICJFMSIsICJFMiIsICJFMyIsICJGMSIsICJGMiIpCgojRGVmaW5lIHBhdGhzCmlucHV0X3BhdGg8LSAiL21udC9sdXN0cmUvc2NyYXRjaC9ubHNhcy9ob21lL2NzaWMvYmllL2xsZi9zZWxlY3Rpb25fc2Nhbi9jaHJfZmlsZXMvIgpvdXRwdXRfcGF0aDwtICIvbW50L2x1c3RyZS9zY3JhdGNoL25sc2FzL2hvbWUvY3NpYy9iaWUvbGxmL3NlbGVjdGlvbl9zY2FuL2lIUy8iCgojbG9vcCB0byBiaW5kIGVhY2ggY2hyX3NwX3NjYW4gZGYgaW4gb25seSBvbmUKZm9yIChjaHIgaW4gY2hyb21vc29tZXMpCnsKICBwcmludCgiU3RhcnRpbmcgbG9vcCIpCiAKICAKICAjUmVhZCB0aGUgc3Vic2V0dGVkIHZjZiAgICAKICBwcmludCAoIlJlYWRpbmcgdmNmIikgIAogIGRhdGE8LSBkYXRhMmhhcGxvaGgoaGFwX2ZpbGU9cGFzdGUwKGlucHV0X3BhdGgsIGNociwgIl8iLCBzcCwgIl8iLCJnb29kc2FtcGxlc19maWx0ZXJlZF9waGFzZWRfcG9sYXJpemVkX3ZhcmlhbnRzX2hlYWRlcl9jYXRfcmVmLnZjZiIpLCBwb2xhcml6ZV92Y2Y9ICJGQUxTRSIsIGFsbGVsZV9jb2Rpbmc9IjAxIiwgY2hyLm5hbWU9Y2hyLCB2Y2ZfcmVhZGVyPSAidmNmUiIpCiAgCiAgI1NjYW4gdGhlIGdlbm9tZSAKICBwcmludCAoIlNjYW5uaW5nIHZjZiIpICAKICBkYXRhX2ZyYW1lPC0gc2Nhbl9oaChkYXRhKSAKICB3cml0ZS50YWJsZShkYXRhX2ZyYW1lLCBmaWxlPShwYXN0ZTAob3V0cHV0X3BhdGgsIGNociwgIl8iLCBzcCwgIl8iLCAic2NhbiIpKSkKICBwcmludCAoIlNhdmVkIHNjYW4gZGF0YSBmcmFtZSIpCiAgCiAgZGY8LSByZWFkLmNzdihwYXN0ZTAob3V0cHV0X3BhdGgsIGNociwgIl8iLCBzcCwgIl8iLCAic2NhbiIpLCBzZXA9IiAiKQogIGRmX3RvdGFsPC0gcmJpbmQoZGZfdG90YWwsZGYpCiAgcHJpbnQoIkFkZGVkIG9uZSBtb3JlIGNociBpbiB0aGUgdG90YWwgZGYiKQp9CgojU2F2ZSB0aGUgc3Bfc2Nhbgp3cml0ZS50YWJsZShkZl90b3RhbCwgZmlsZT0ocGFzdGUwKG91dHB1dF9wYXRoLCBzcCwgIl9zY2FuIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgojQ2FsY3VsYXRlIGdlbm9tZS13aWRlIGlIUyB2YWx1ZXMKcHJpbnQgKCJDYWxjdWxhdGluZyBpaHMiKSAKd2dzY2FuLmloczwtIGloaDJpaHMoZGZfdG90YWwsIChyb3VuZCgobWluKGRmX3RvdGFsJEZSRVFfQSkgKiAyKSwgMikpKSAKd3JpdGUudGFibGUod2dzY2FuLmlocyRpaHMsIGZpbGU9KHBhc3RlMChvdXRwdXRfcGF0aCwgc3AsICJfaWhzX3NjYW4iKSksIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKcHJpbnQgKCJTYXZlZCBpaHMgZGF0YSBmcmFtZSIpCmBgYAoKIyMjIDEuMiBYUC1FSEggYW5hbHlzZXMKCkFzIHdpdGggaUhTLCBJIHVzZWQgcmVoaCBSIHBhY2thZ2UuIFRoZSBlbnRpcmUgY29kZSBpcyBhdmFpbGFibGUgaW4geHBlaGhfc3AuUi4gVG8gcnVuIHRoaXMgaW4gQ0VTR0EsIEkgaGFkIHRvIGNyZWF0ZSBhIHJ1bl94cGVoaC5zaCBzY3JpcHQgdGhhdCBzcGVjaWZ5IHRvIHJ1biB0aGUgUnNjcmlwdC4KCmBgYHtyIGV2YWw9RkFMU0V9CiMhL3Vzci9iaW4vZW52IFJzY3JpcHQKCnByaW50ICgiU3RhcnRpbmcgeHBlaGggYW5hbHlzaXMiKQoKI2luc3RhbGwucGFja2FnZXMoInZjZlIiKQojaW5zdGFsbC5wYWNrYWdlcygicmVoaCIpCmxpYnJhcnkodmNmUikKbGlicmFyeShyZWhoKQoKI0RlZmluZSBwYXRocwpwYXRoPC0gIi9tbnQvbHVzdHJlL3NjcmF0Y2gvbmxzYXMvaG9tZS9jc2ljL2JpZS9sbGYvc2VsZWN0aW9uX3NjYW4vaUhTLyIKCiNOYW1lIHZhcmlhYmxlcwpzcGVjaWVzPC0gYygibGMiLCAibGwiLCAibHAiLCAibHIiKQoKI1JlYWQgcGVyIHNwIHNjYW4KICBmb3Ioc3AgaW4gc3BlY2llcykgCiAgICB7CiAgICBwcmludChwYXN0ZSgiUmVhZGluZyIsIHNwLCAic2NhbiIpKQogICAgc2NhbjwtIHJlYWQuY3N2KHBhc3RlMChwYXRoLCBzcCwgIl9zY2FuIiksIHNlcD0iXHQiKQogICAgYXNzaWduKHBhc3RlMChzcCwgIl9zY2FuIiksIHNjYW4pCiAgfQoKI0NhbGN1bGF0aW5nIFhQLUVISApwcmludCAoIkNhbGN1bGF0aW5nIHhwZWhoIikgCgpsY19sbF94cGVoaCA8LSBpZXMyeHBlaGgoc2Nhbl9wb3AxID0gbGNfc2Nhbiwgc2Nhbl9wb3AyID0gbGxfc2NhbiwgcG9wbmFtZTEgPSAiTEMiLCBwb3BuYW1lMiA9ICJMTCIsIHAuYWRqdXN0Lm1ldGhvZCA9ICJmZHIiKQp3cml0ZS50YWJsZShsY19sbF94cGVoaCwgZmlsZT0ocGFzdGUwKHBhdGgsICJsY19sbF94cGVoaF9zY2FuIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgpsY19scF94cGVoaCA8LSBpZXMyeHBlaGgoc2Nhbl9wb3AxID0gbGNfc2Nhbiwgc2Nhbl9wb3AyID0gbHBfc2NhbiwgcG9wbmFtZTEgPSAiTEMiLCBwb3BuYW1lMiA9ICJMUCIsIHAuYWRqdXN0Lm1ldGhvZCA9ICJmZHIiKQp3cml0ZS50YWJsZShsY19scF94cGVoaCwgZmlsZT0ocGFzdGUwKHBhdGgsICJsY19scF94cGVoaF9zY2FuIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgoKbGNfbHJfeHBlaGggPC0gaWVzMnhwZWhoKHNjYW5fcG9wMSA9IGxjX3NjYW4sIHNjYW5fcG9wMiA9IGxyX3NjYW4sIHBvcG5hbWUxID0gIkxDIiwgcG9wbmFtZTIgPSAiTFIiLCBwLmFkanVzdC5tZXRob2QgPSAiZmRyIikKd3JpdGUudGFibGUobGNfbHJfeHBlaGgsIGZpbGU9KHBhc3RlMChwYXRoLCAibGNfbHJfeHBlaGhfc2NhbiIpKSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQoKCmxsX2xwX3hwZWhoIDwtIGllczJ4cGVoaChzY2FuX3BvcDEgPSBsbF9zY2FuLCBzY2FuX3BvcDIgPSBscF9zY2FuLCBwb3BuYW1lMSA9ICJMTCIsIHBvcG5hbWUyID0gIkxQIiwgcC5hZGp1c3QubWV0aG9kID0gImZkciIpCndyaXRlLnRhYmxlKGxsX2xwX3hwZWhoLCBmaWxlPShwYXN0ZTAocGF0aCwgImxsX2xwX3hwZWhoX3NjYW4iKSksIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKCgpsbF9scl94cGVoaCA8LSBpZXMyeHBlaGgoc2Nhbl9wb3AxID0gbGxfc2Nhbiwgc2Nhbl9wb3AyID0gbHJfc2NhbiwgcG9wbmFtZTEgPSAiTEwiLCBwb3BuYW1lMiA9ICJMUiIsIHAuYWRqdXN0Lm1ldGhvZCA9ICJmZHIiKQp3cml0ZS50YWJsZShsbF9scl94cGVoaCwgZmlsZT0ocGFzdGUwKHBhdGgsICJsbF9scl94cGVoaF9zY2FuIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCgoKbHBfbHJfeHBlaGggPC0gaWVzMnhwZWhoKHNjYW5fcG9wMSA9IGxwX3NjYW4sIHNjYW5fcG9wMiA9IGxyX3NjYW4sIHBvcG5hbWUxID0gIkxQIiwgcG9wbmFtZTIgPSAiTFIiLCBwLmFkanVzdC5tZXRob2QgPSAiZmRyIikKd3JpdGUudGFibGUobHBfbHJfeHBlaGgsIGZpbGU9KHBhc3RlMChwYXRoLCAibHBfbHJfeHBlaGhfc2NhbiIpKSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQoKYGBgCgojIyMgMS4zLiBzYWx0aS1MQVNTSQoKSGVyZSBJIGFtIGdvaW5nIHRvIHVzZSBzYWx0aUxBU1NJIHRvIGFuYWx5c2Ugc2VsZWN0aW9uIGZyb20gaGFwbG90eXBlIGZyZXF1ZW5jeSBzcGVjdHJ1bSAoSEZTKS4gSSB1c2VkIHdpbmRvd3Mgb2YgMTAxIFNOUFMgd2l0aCBhIDUwIHNsaWRlLiBUaGUgZW50aXJlIGNvZGUgaXMgYXZhaWxhYmxlIGluIGxhc3NpLnNoLgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KCnNwZWNpZXM9KGxjIGxsIGxwIGxyKQoKZm9yIHNwIGluICR7c3BlY2llc1tAXX0KICBkbwogICAgZWNobyAiJHNwIgogICAgI21ha2UgYSBzcF9pbmQudHh0IChwb3AgZmlsZSkgbmVlZGVkIGZvciBsYXNzaXAKICAgIHNlZCAicy8kL1x0JHtzcH0vIiA8KGdyZXAgIiNDSFIiICRMVVNUUkUvJHtzcH1fZ29vZHNhbXBsZXNfZmlsdGVyZWRfcGhhc2VkX3BvbGFyaXplZF92YXJpYW50c19oZWFkZXJfY2F0X3JlZi52Y2YgfCB0ciAiXHQiICJcbiIgfCBncmVwICR7c3B9KSAgPiAkTFVTVFJFL3NlbGVjdGlvbl9zY2FuLyR7c3B9X2luZC50eHQKICAgIHNiYXRjaCBsYXNzaS5zaCAkc3AKICBkb25lICAKICAKc3BlY2llcz0obGMgbGwgbHAgbHIpCgpmb3Igc3AgaW4gJHtzcGVjaWVzW0BdfQogIGRvCiAgc2JhdGNoIGxhc3NpLnNoICRzcAogIGRvbmUKYGBgCgojIyAyLiBSZXN1bHRzCgojIyMgMi4xIFJlcHJlc2VudGF0aW9uIG9mIGlIUyBhbmQgc2FsdGktTEFTU0kgcmVzdWx0cwoKRm9yIGdyYXBoaWNzIHdlIGFyZSBnb2luZyB0byB1c2UgUi4gRmlyc3QgdGhpbmcgaXMgdG8gcnVuIHBhY2thZ2VzIG5lZWRlZCBhbmQgc2V0IGRpcmVjdG9yaWVzLgoKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlaGgpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ2dyZXBlbCkKCiNTZXQgZGlyZWN0b3JpZXMKcGF0aDwtICIvVXNlcnMvbG9yZW5hbG9yZW56byIKZmlsZXM8LSAiL2ZpbGVzLyIKcGxvdHM8LSAiL3Bsb3RzLyIKCiNOYW1lIHRoZSB2YXJpYWJsZXMKc3BlY2llczwtIGMoImxjIiwgImxsIiwgImxwIiwgImxyIikKCm5hbWVzIDwtIGMoImxjIiA9ICJMeW54IGNhbmFkZW5zaXMiLAogICAgICAgICAgICAibHIiID0gIkx5bnggcnVmdXMiLAogICAgICAgICAgICAibGwiID0gIkx5bnggbHlueCIsCiAgICAgICAgICAgICJscCIgPSAiTHlueCBwYXJkaW51cyIpCgpjaHIgPC0gYyggIkExIiwgIkEyIiwgIkEzIiwgIkIxIiwgIkIyIiwgIkIzIiwgIkI0IiwgIkMxIiwgIkMyIiwgIkQxIiwgIkQyIiwgIkQzIiwgIkQ0IiwgIkUxIiwgIkUyIiwgIkUzIiwgIkYxIiwgIkYyIiwgIlgiKQoKY29sb3JzIDwtIGMoImxjIj0gIiNBQjk3QjciLAogICAgICAgICAgICAibGwiPSAiI0YyQUI1QSIsCiAgICAgICAgICAgICJscCI9IiNFQjU5NUYiLAogICAgICAgICAgICAibHIiPSIjNzFDMTc4IikKI3ByaW50KGFzLmNoYXJhY3RlcihuYW1lc1tzcGVjaWVzXSkpCiNwcmludChhcy5jaGFyYWN0ZXIoY29sb3JzW3NwZWNpZXNdKSkKCiNzZXQgWCBheGlzIHdpdGggY2hyX3NpemUgZGF0YWZyYW1lIChmb3IgcGxvdHRpbmcpCiAgICBheGlzX3NldCA8LSByZWFkLnRhYmxlKHBhc3RlMChwYXRoLCBmaWxlcywgImNocl9zaXplLnR4dCIpLCBzZXA9Ilx0IiwgY29sLm5hbWVzPWMoImNociIsICJzaXplIikpICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShjZW50ZXIgPSBzaXplLzIpCiAgICAjR3JvdXAgYnkgY2hyCiAgICBkYXRhX2F4aXMgPC0gYXhpc19zZXQgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZShzaXplX2N1bSA9IGxhZyhjdW1zdW0oYXMubnVtZXJpYyhzaXplKSksIGRlZmF1bHQgPSAwKSkgJT4lCiAgICAgICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKGNlbnRlcl9jdW0gPSBzdW0oY2VudGVyLCBzaXplX2N1bSkpICAgICAKYGBgCgpJbiB0aGUgZm9sbG93aW5nIGNvZGUgSSBwcmVwYXJlIGlIUyBhbmQgc2FsdGlMQVNTSSByZXN1bHRzIGZvciByZXByZXNlbnRhdGlvbiB3aXRoIGN1dG9mZnMuCgpgYGB7cn0KCmZvciAoc3AgaW4gc3BlY2llcykKewoKIyBpSFMgcmVzdWx0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgaWhzX3NjYW4gPC0gcmVhZC50YWJsZShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwICwgIl9paHNfc2NhbiIpLCBzZXA9Ilx0IiwgaGVhZGVyPSBUUlVFLCBjb2wubmFtZXMgPSBjKCJjaHIiLCAicG9zIiwgImlocyIsICJwdmFsIikpCiAgcHJpbnQoIlJlYWQgaWhzX3NjYW4gZGF0YSIpCiAgCiAgI0dyb3VwIGJ5IGNocgogIGRhdGFfY3VtIDwtIGloc19zY2FuICU+JSAKICAgIGdyb3VwX2J5KGNocikgJT4lIAogICAgc3VtbWFyaXNlKG1heF9icCA9IG1heChwb3MpKSAlPiUKICAgIG11dGF0ZShicF9hZGQgPSBsYWcoY3Vtc3VtKG1heF9icCksIGRlZmF1bHQgPSAwKSkgJT4lIAogICAgc2VsZWN0KGNociwgYnBfYWRkKQogIAogIGRhdGFfaWhzIDwtIGloc19zY2FuICU+JSAKICAgIGlubmVyX2pvaW4oZGF0YV9jdW0sIGJ5ID0gImNociIpICU+JSAKICAgIG11dGF0ZShicF9jdW0gPSBwb3MgKyBicF9hZGQpICU+JQogICAgbmEub21pdCgpICU+JQogICAgbXV0YXRlKGFic19paHM9IGFicyhpaHMpKSAlPiUgI2Fic29sdXRlIHZhbHVlIHNjb3JlIG9mIGlIUwogICAgbXV0YXRlIChkYXRhc2V0PSJ8aUhTfCIpICAjZm9yIGZhY2V0X2dyaWQKICAKICBheGlzX3NldCA8LSBkYXRhX2locyAlPiUgCiAgICBncm91cF9ieShjaHIpICU+JSAKICAgIHN1bW1hcml6ZShjZW50ZXIgPSBtZWFuKGJwX2N1bSkpCiAgCiAgcHJpbnQoIkRhdGEgc2V0IikKICAgIAp3cml0ZS50YWJsZShkYXRhX2locywgZmlsZT0ocGFzdGUwKHBhdGgsIGZpbGVzLCBzcCwgImRhdGFfaWhzIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCiAgCiAgI2V4cGxvcmUgaWhzIGRpc3RyaWJ1dGlvbiAoZ2F1c3NpYW4pCiAgIyBwZGYocGFzdGUwKHBhdGgsIHBsb3RzLCBzcCwiX2Rpc3RwbG90LnBkZiIpLCB3aWR0aD0xMCwgaGVpZ2h0PTUpCiAgIyBkaXN0cmlicGxvdChpaHNfc2NhbiRJSFMsIHhsYWI9IHBhc3RlKHNwLCAiaUhTIiksIHFxcGxvdCA9IFRSVUUpCiAgI2Rldi5vZmYoKQogIAojIyBkZWZpbmUgb3V0bGllcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogIGloc19vdXRsaWVyczwtIGRhdGFfaWhzICU+JSBmaWx0ZXIoYWJzX2locyA+PSA0KQogIHByaW50KGxlbmd0aChpaHNfb3V0bGllcnMkYWJzX2locykpCiAgCiAgd3JpdGUudGFibGUoaWhzX291dGxpZXJzLCBmaWxlPShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiX2loc180b3V0bGllcnMiKSksIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKICBwcmludCgib3V0bGllcnMgZGYgc2F2ZWQiKQogIAogICNTYXZlIGFzIDAtYmFzZWQgYmVkIGZpbGUKIGJlZF80IDwtIGloc19vdXRsaWVycyAlPiUgbXV0YXRlKHN0YXJ0PSBwb3MgLSAxKSAlPiUgc2VsZWN0KGMoMSw5LDIsMyw3KSkKIHdyaXRlLnRhYmxlKGJlZF80LCBmaWxlPShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiX2loc180b3V0bGllcnMuYmVkIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQoKICAKIyBzYWx0aUxBU1NJIHJlc3VsdHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICBwcmludCgiU3RhcnRpbmcgcGxvdHRpbmcgTEFTU0kgcmVzdWx0cyBjb2RlIikKCiAgI1JlYWQgZGF0YQogIGxhc3NpX3NjYW48LSByZWFkLnRhYmxlKHBhc3RlMChwYXRoLCBmaWxlcywgc3AsICJfc2FsdGkubGFzc2lwLmhhcC5vdXQiKSwgc2VwPSJcdCIsIGhlYWRlcj1UKQogIHByaW50KHBhc3RlKCJSZWFkIGRhdGEgZm9yIiwgc3ApKQogIAogICNHcm91cCBieSBjaHIKICBkYXRhX2N1bSA8LSBsYXNzaV9zY2FuICU+JSAKICAgIGdyb3VwX2J5KGNocikgJT4lIAogICAgc3VtbWFyaXNlKG1heF9icCA9IG1heChwb3MpKSAlPiUKICAgIG11dGF0ZShicF9hZGQgPSBsYWcoY3Vtc3VtKG1heF9icCksIGRlZmF1bHQgPSAwKSkgJT4lIAogICAgc2VsZWN0KGNociwgYnBfYWRkKQogIAogIGRhdGFfbGFzc2kgPC0gbGFzc2lfc2NhbiAlPiUgCiAgICBpbm5lcl9qb2luKGRhdGFfY3VtLCBieSA9ICJjaHIiKSAlPiUgCiAgICBtdXRhdGUoYnBfY3VtID0gcG9zICsgYnBfYWRkKSAlPiUKICAgIG11dGF0ZShkYXRhc2V0PSJzYWx0aUxBU1NJIikKICAKICBheGlzX3NldCA8LSBkYXRhX2xhc3NpICU+JSAKICAgIGdyb3VwX2J5KGNocikgJT4lIAogICAgc3VtbWFyaXplKGNlbnRlciA9IG1lYW4oYnBfY3VtKSkKICAKICBwcmludCgiQWN1bXVsYXRlZCBieSBjaHIiKQogIAogIAogICNDaGFuZ2UgdGhlICJzcF9MIiBjb2x1bW4gbmFtZSB0byBhbm90aGVyIGluIG9yZGVyIHRvIG1ha2UgaXQgZWFzaWVyIHRvIG1hbmFnZQogIGNvbG5hbWVzKGRhdGFfbGFzc2kpWzEyXTwtICJzdGF0aXN0aWMiCiAgCiAgcHJpbnQoInJlbmFtZSBzcF9MIGNvbHVtbiB0byBzdGF0aXN0aWMiKQogIAogIHdyaXRlLnRhYmxlKGRhdGFfbGFzc2ksIGZpbGU9KHBhc3RlMChwYXRoLCBmaWxlcywgc3AsICJkYXRhX2xhc3NpIikpLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIHF1b3RlID0gRkFMU0UpCiAgCiAgI0V4cGxvcmUgc3RhdGlzdGljIGRpc3RyaWJ1dGlvbgogICAgI3BkZihwYXN0ZTAocGF0aCwgcGxvdHMsIHNwLCJfTF9zdGF0aXN0aWNfZGlzdHBsb3QucGRmIiksIHdpZHRoPTEwLCBoZWlnaHQ9NSkKICAKICAgICNwcmludChnZ3Bsb3QoZGF0YV9sYXNzaSwgYWVzKHg9IHN0YXRpc3RpYykpICsKICAgICAgICAgIyBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoPTEwKSArIAogICAgICAgICAjIHlsaW0oMCwgMjAwMDApICsKICAgICAgICAjICBsYWJzICh0aXRsZT1zcCkpCiAgCiAgICNkZXYub2ZmKCkKICAKICAgICNwcmludCgiZGlzdHJpYnV0aW9uIHBsb3Qgc2F2ZWQiKQogIAojIyBkZWZpbmUgb3V0bGllcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgI2N1dC1vZmYgOTUlCiAgcHJpbnQocGFzdGUoc3AsIHJvdW5kKGxlbmd0aChkYXRhX2xhc3NpJHN0YXRpc3RpYykgKiAwLjA1KSwgInRvcCA1JSB2YWx1ZXMiKSkKICBjdXRfOTUgPC0gc29ydChkYXRhX2xhc3NpJHN0YXRpc3RpYylbcm91bmQobGVuZ3RoKGRhdGFfbGFzc2kkc3RhdGlzdGljKSAqIDAuOTUpXQogIHByaW50KHBhc3RlKHNwLCBjdXRfOTUsICI1JSBjdXQtb2ZmIiApKQogIAogIGxhc3NpX291dGxpZXJzXzk1PC0gZGF0YV9sYXNzaSAlPiUgZmlsdGVyKHN0YXRpc3RpYyA+PSBjdXRfOTUpCiAgd3JpdGUudGFibGUobGFzc2lfb3V0bGllcnNfOTUsIGZpbGU9KHBhc3RlMChwYXRoLCBmaWxlcywgc3AsICJfbGFzc2lfNSVvdXRsaWVycyIpKSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQogIHByaW50KCJvdXRsaWVycyBkZiBzYXZlZCIpCiAgCiAgYmVkXzk1IDwtIGxhc3NpX291dGxpZXJzXzk1ICAlPiUgc2VsZWN0KGMoMSwyLDMsMTIpKQogIHdyaXRlLnRhYmxlKGJlZF85NSwgZmlsZT0ocGFzdGUwKHBhdGgsIGZpbGVzLCBzcCwgIl9sYXNzaV81JW91dGxpZXJzLmJlZCIpKSwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKfSAgCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDE1fQojIHBsb3QgaUhTICYgbGFzc2kgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KZm9yIChzcCBpbiBzcGVjaWVzKQp7CiAgCiNSZWFkIGRhdGEKZGF0YV9paHM8LSByZWFkLnRhYmxlKHBhc3RlMChwYXRoLCBmaWxlcywgc3AsICJkYXRhX2locyIpLCBoZWFkZXIgPSBUUlVFKQpkYXRhX2xhc3NpPC0gcmVhZC50YWJsZShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiZGF0YV9sYXNzaSIpLCBoZWFkZXIgPSBUUlVFKQoKCnA8LSAKICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9wb2ludChkYXRhX2locywgbWFwcGluZz1hZXMoeD0gYnBfY3VtLCB5PWFicyhpaHMpLCBhbHBoYSA9IDAuNSwgY29sb3IgPSBhc19mYWN0b3IoY2hyKSkpICsgCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVsID0gZGF0YV9heGlzJGNociwgYnJlYWtzID0gZGF0YV9heGlzJGNlbnRlcl9jdW0pICsgICAgIAogICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PSA0LCBjb2xvcj0icmVkIiwgbGluZXR5cGU9ImRhc2hlZCIpICsKICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0gLTQsIGNvbG9yPSJyZWQiLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgICAgeWxhYiAoImlIUyIpICsKICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE1LGZhY2U9ImJvbGQiKSkgKwogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1yZXAoYyhhcy5jaGFyYWN0ZXIoY29sb3JzW3NwXSksICIjQ0NEMUQxIiksIDE4ICkpCgoKCnE8LSBnZ3Bsb3QoKSArCiAgICAgICBnZW9tX3BvaW50KGRhdGFfbGFzc2ksIG1hcHBpbmc9YWVzKHggPSBicF9jdW0sIHkgPSBzdGF0aXN0aWMsIGFscGhhID0gMC41LCBjb2xvciA9IGFzX2ZhY3RvcihjaHIpKSkgKyAgIAogICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PSBjdXRfOTUsIGNvbG9yPSJyZWQiLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVsID0gZGF0YV9heGlzJGNociwgYnJlYWtzID0gZGF0YV9heGlzJGNlbnRlcl9jdW0pICsKICAgICAgIHlsYWIgKCLOmyIpICsKICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE1LGZhY2U9ImJvbGQiKSkgKwogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1yZXAoYyhhcy5jaGFyYWN0ZXIoY29sb3JzW3NwXSksICIjQ0NEMUQxIiksIDE4ICkpCgpyPC0gZ2dhcnJhbmdlKHAscSwgbnJvdz0gMiwgbmNvbD0gMSkgCgpyIDwtIGFubm90YXRlX2ZpZ3VyZShyLAogICAgICAgICAgICAgICAgdG9wID0gdGV4dF9ncm9iKGFzLmNoYXJhY3RlcihuYW1lc1tzcF0pLCBmYWNlID0gIml0YWxpYyIsIHNpemUgPSAzMCksCiAgICAgICAgICAgICAgICAjbGVmdCA9IHRleHRfZ3JvYigiU3RhdGlzdGljIHZhbHVlIiwgY29sb3IgPSAiZ3JleSIsIHJvdCA9IDkwKSwKICAgICAgICAgICAgICAgICkKYXNzaWduKHBhc3RlMChzcCwgIl9wbG90IiksIHIgKQoKfQoKIyMgY3VzdG9taXplCnM8LSBnZ2FycmFuZ2UobGNfcGxvdCwgbGxfcGxvdCwgbHBfcGxvdCwgbHJfcGxvdCwgCiAgICAgbmNvbD0gMiwgbnJvdz0gMiwKICAgICBjb21tb24ubGVnZW5kPSBUUlVFLAogICAgICAgbGVnZW5kPSJib3R0b20iKSAgCgpwcmludChzKQpgYGAKCiMjIyAyLjIgSW50ZXJzZWN0IGJldHdlZW4gbWV0aG9kcwoKT25jZSBzYXZlZCB0aGUgb3V0bGllcnMgYmVkIGZyb20gaUhTIGFuZCBzYWx0aUxBU1NJLCB3ZSBuZWVkIHRoZSBvdmVybGFwIG9mIGJvdGggbWV0aG9kcy4gRm9yIGRvaW5nIHRoYXQsIGhlcmUgd2UgYXJlIHVzaW5nIGJlZHRvb2xzLiBGaXJzdGx5LCBJIG1lcmdlIGV2ZXJ5IG92ZXJsYXBwaW5nIG91dGxpZXIgd2luZG93IGZyb20gbGFzc2kuIFRoZW4sIHdlIGludGVyc2VjdCB0aGlzIHdpbmRvd3Mgd2l0aCB0aGUgb3V0bGllciBTTlBzIGZyb20gaUhTIHRvIGdldCBwdXRhdGl2ZSBzZWxlY3RlZCBnZW5vbWljIFJFR0lPTlMuIFVzZSA1JSBhcyBjdXRvZmYgZm9yIGxhc3NpIGJlY2F1c2UgYWZ0ZXIgdGhhdCB3ZSBhcmUgZ29pbmcgdG8gcmFuayAxMCBiZXN0IHJlZ2lvbnMuCgpgYGB7YmFzaCBldmFsPUZBTFNFfQptb2R1bGUgbG9hZCBiZWR0b29scwoKc3BlY2llcz0obGMgbGwgbHAgbHIpCgpmb3Igc3AgaW4gJHtzcGVjaWVzW0BdfQogIGRvCiAgICBlY2hvICIkc3AiCiAgICAgICAjbWVyZ2UgZXZlcnkgb3ZlcmxhcHBpbmcgb3V0bGllciB3aW5kb3cgaW4gTEFTU0kgCiAgICAgICBiZWR0b29scyBtZXJnZSBcCiAgICAgICAtaSAke3NwfV9sYXNzaV81JW91dGxpZXJzLmJlZCBcCiAgICAgICAtYyAxIFwKICAgICAgIC1vIGNvdW50IFwKICAgICAgID4gJHtzcH1fbWVyZ2VkX3RtcAogICAgICAgZWNobyAiJHNwIG1lcmdlZCIKICAgICAgIAogICAgICAgI2ludGVyc2VjdCB3aXRoIGlIUyBzbnBzIHNvIHRoZSByZXN1bHQgYXJlIEdFTk9NSUMgUkVHSU9OUyB1bmRlciBwdXRhdGl2ZSBzZWxlY3Rpb24KICAgICAgIGJlZHRvb2xzIGludGVyc2VjdCBcCiAgICAgICAtYSAke3NwfV9tZXJnZWRfdG1wIFwKICAgICAgIC1iICR7c3B9X2loc180b3V0bGllcnMuYmVkIFwKICAgICAgIC1jIFwKICAgICAgID4gJHtzcH1faW50ZXJzZWN0ZWRfdG1wCiAgICAgICBlY2hvICIkc3AgaW50ZXJzZWN0ZWQiCiAgICAgICAKICAgICAgICNhZGQgc25wIGRlbnNpdHkgICAgICAgIAogICAgICAgYmVkdG9vbHMgaW50ZXJzZWN0IFwKICAgICAgIC1hICR7c3B9X2ludGVyc2VjdGVkX3RtcCBcCiAgICAgICAtYiAkTFVTVFJFL3ZjZnMvJHtzcH1fZ29vZHNhbXBsZXNfZmlsdGVyZWRfcGhhc2VkX3BvbGFyaXplZF92YXJpYW50c19oZWFkZXJfY2F0X3JlZi52Y2YgXAogICAgICAgLWMgXAogICAgID4gJHtzcH1fc25wc19kZW5zaXR5X3RtcAogICAgIAogICAgICAgI2NhbGN1bGF0ZSBsYXNzaSB2YWx1ZXMgZm9yIHRob3NlIHJlZ2lvbnMKICAgICAgIGJlZHRvb2xzIG1hcCBcCiAgICAgICAtYSAke3NwfV9zbnBzX2RlbnNpdHlfdG1wXAogICAgICAgLWIgJHtzcH1fbGFzc2lfNSVvdXRsaWVycy5iZWQgXAogICAgICAgLUYgMSBcCiAgICAgICAtYyA0IFwKICAgICAgIC1vIG1lYW4sbWF4LHN1bSBcCiAgICAgICA+ICR7c3B9X2xhc3NpX3RtcAogICAgICAgZWNobyAiJHNwIGxhc3NpIHN0YXRpc3RpY3MgY2FsY3VsYXRlZCIKICAgICAgIAogICAgICAgI2NhbGN1bGF0ZSBpSFMgdmFsdWVzIGZvciB0aG9zZSByZWdpb25zCiAgICAgICBiZWR0b29scyBtYXAgXAogICAgICAgLWEgJHtzcH1fbGFzc2lfdG1wIFwKICAgICAgIC1iICR7c3B9X2loc180b3V0bGllcnMuYmVkIFwKICAgICAgIC1GIDEgXAogICAgICAgLWMgNSBcCiAgICAgICAtbyBtZWFuLG1heCxzdW0gXAogICAgICAgPiAke3NwfV9sYXNzaV9paHNfdG1wCiAgICAgICBlY2hvICIkc3AgaWhzIHN0YXRpc3RpY3MgY2FsY3VsYXRlZCIKICAgICAgIAogICAgICAgI3JlbW92ZSAwJ3MgKG5vIFNOUFMpCiAgICAgICBhd2sgLUYgJ1x0JyAnJDUgIT0gMCcgJHtzcH1fbGFzc2lfaWhzX3RtcCA+ICR7c3B9X2xhc3NpX2loc19yZWdpb25zX3RtcAogICAgICAgZWNobyAiJHNwIHJlZ2lvbnMgd2l0aCAwIHNucHMgaW50ZXJzZWN0ZWQgcmVtb3ZlZCIKICAgICAgIAogICAgICAgI3ByaW50IGEgaGVhZGVyIChjb2x1bW4gbmFtZXMpCiAgICAgICBlY2hvIC1lICJjaHIgc3RhcnQgZW5kIHdpbmRvd3Mgc25wcyBzbnBzX2RlbnNpdHkgbGFzc2lfbWVhbiBsYXNzaV9tYXggbGFzc2lfc3VtIGloc19tZWFuIGloc19tYXggaWhzX3N1bSIgfCBjYXQgLSAke3NwfV9sYXNzaV9paHNfcmVnaW9uc190bXAgfCB0ciAiICIgIlx0IiA+ICR7c3B9X2xhc3NpX2loc19yZWdpb25zIAogICAgICAgCiAgIyMjIyMjQ3Jvc3MgYmVkIHJlc3VsdHMgd2l0aCBhbm5vdGF0aW9uIGZpbGUgKGdmZjMpICAgIAogICAgICAjbWF0Y2ggc2VsZWN0ZWQgcmVnaW9ucyB3aXRoIGdlbm9tZSBhbm5vdGF0aW9uCiAgICAgICBiZWR0b29scyBpbnRlcnNlY3QgXAogICAgICAgICAtYSAke3NwfV9sYXNzaV9paHNfcmVnaW9uc190bXAgXAogICAgICAgICAtYiAkU1RPUkUyL3JlZmVyZW5jZV9nZW5vbWVzL0ZlbGlzX2NhdHVzX1JlZi9GZWxpc19jYXR1cy5GZWxpc19jYXR1c185LjAuOTcuZ2ZmMyBcCiAgICAgICAgIC13YSAtd2IgXAogICAgICAgICA+ICR7c3B9X2Fubm90YXRlZF90bXAgCiAgICAgICAgZWNobyAiJHNwIGFubm90YXRlZCIKICAgICAgICAKICAgICAgI2ZpbHRlciBvbmx5IGdlbmVzCiAgICAgIGF3ayAnJDE1PT0iZ2VuZSInICR7c3B9X2Fubm90YXRlZF90bXAgPiAke3NwfV9nZW5lX3RtcAogICAgICBlY2hvICIkc3AgZ2VuZSBmaWx0ZXJlZCIKICAgIAogICAgI2dldCBvbmx5IGludGVyZXN0aW5nIGNvbHVtbnMKICAgIGN1dCAtZi0xMiwxNiwxNywyMS0gJHtzcH1fZ2VuZV90bXAgfCB0ciAnICcgJ1x0JyA+ICR7c3B9X2ZpbHRlcmVkX3RtcAogICAgCiAgICAjZW5zZW1ibCBpZCBhbmQgZ2VuZSBuYW1lIGFzIGNvbHVtbiBkYXRhCiAgICBjdXQgLWQnOycgLWYxLDIgJHtzcH1fZmlsdGVyZWRfdG1wIHwgdHIgJzsnICdcdCcgIHwgYXdrICd7aWYgKCQxNiB+IC9OYW1lPVtbOmFsbnVtOl1dLykgJDE2PSQxNjsgZWxzZSAkMTY9Ik5BIjsgcHJpbnQgJDB9JyA+ICR7c3B9X25hbWVzX3RtcCAKICAgIAogICAgI2N1dCBleHRyYS1pbmZvIGZyb20gZW5zIGNvZGUgYW5kIGdlbmUgbmFtZSBjb2x1bW5zCiAgICBwYXN0ZSA8KGN1dCAtZCIgIiAtZi0xNCAke3NwfV9uYW1lc190bXApIDwoY3V0IC1kIiAiIC1mMTUgJHtzcH1fbmFtZXNfdG1wIHwgY3V0IC1kIjoiIC1mMikgPChjdXQgLWQiICIgLWYxNiAke3NwfV9uYW1lc190bXAgfCBjdXQgLWQiPSIgLWYyKSB8ICB0ciAiXHQiICIgIiAgPj4gJHtzcH1fY29sdW1uc190bXAKICAgIAogICAgI3ByaW50IGEgaGVhZGVyIChjb2x1bW4gbmFtZXMpCiAgICBlY2hvIC1lICJjaHIgc3RhcnQgZW5kIHdpbmRvd3Mgc25wcyBzbnBzX2RlbnNpdHkgbGFzc2lfbWVhbiBsYXNzaV9tYXggbGFzc2lfc3VtIGloc19tZWFuIGloc19tYXggaWhzX3N1bSBnZW5lX3N0YXJ0IGdlbmVfZW5kIGVuc2VtYmxfaWQgZ2VuZV9uYW1lIiB8IGNhdCAtICR7c3B9X2NvbHVtbnNfdG1wID4gJHtzcH1fZ2Vub21pY19yZWdpb25zX2Fubm90YXRlZAogICAgICAKICAgICAgICAjcmVtb3ZlIHRlbXBvcmFsIGZpbGVzCiAgICAgICBybSAqdG1wCiAgICBkb25lCmBgYAoKIyMjIDIuMyBSZXByZXNlbnRhdGlvbiBvZiB0aGUgaW50ZXJzZWN0aW9uCgpGb3IgcmVwcmVzZW50YXRpb24gcHVycG9zZXMsIEkgd2FudCB0byBtZXJnZSBsYXNzaSBvdXRsaWVycyB3aW5kb3dzIGRhdGEgd2l0aCBpbnRlcnNlY3RlZCBvdXRpbGllcyByZWdpb25zIGRhdGEuCgpgYGB7YmFzaCBldmFsPUZBTFNFfQptb2R1bGUgbG9hZCBiZWR0b29scwoKc3BlY2llcz0obGMgbGwgbHAgbHIpCgojTWVyZ2UgaW5mbyBhYm91dCBsYXNzaSByZXN1bHRzIGFuZCB0aGUgZmluYWwgdGFibGUgb2YgZ2Vub21pY3MgcmVnaW9ucyB1bmRlciBzZWxlY3Rpb24KZm9yIHNwIGluICR7c3BlY2llc1tAXX0KICBkbwogICAgZWNobyAiJHNwIgogICAgYmVkdG9vbHMgaW50ZXJzZWN0IFwKICAgIC1hIDwoZ3JlcCAtdiAiY2hyIiBzYWx0aUxBU1NJLyR7c3B9X3NhbHRpLmxhc3NpcC5oYXAub3V0IHwgY3V0IC1mMSwyLDMsNSwxMikgXAogICAgLWIgPChncmVwIC12ICJjaHIiICR7c3B9XzUlb3V0bGllcnNfdGFibGUpIFwKICAgIC13YW8gXAogICAgPiAke3NwfV9yZXN1bHRzX3RhYmxlX3JlcHJlc2VudGF0aW9uCiAgZG9uZSAgCmBgYAoKYGBge3IgICwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTV9CiMjIHBsb3QgcmVzdWx0cyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpmb3IgKHNwIGluIHNwZWNpZXMpCnsKICAjUmVhZCB0aGUgZGF0YQogIGRhdGFfYWxsIDwtIHJlYWQudGFibGUocGFzdGUwKHBhdGgsZmlsZXMsIHNwLCAiX3Jlc3VsdHNfdGFibGVfcmVwcmVzZW50YXRpb24iKSwgc2VwPSJcdCIsIGhlYWRlcj0gRkFMU0UsIG5hLnN0cmluZ3MgPSAiLiIsIGNvbC5uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicG9zIiwgInN0YXRpc3RpYyIsICJyX2NociIsICJyX3N0YXJ0IiwgInJfZW5kIiwgIm5fd2luZG93cyIsICJuX3NucHMiLCAid2VpZ2h0ZWRfc3RhdGlzdGljIiwgIndpbmRvd19zaXplIiwgIndlaWdodCIsICJicF9vdmVybGFwIikpICAgJT4lIAogICAgaW5uZXJfam9pbihkYXRhX2F4aXMsIGJ5ID0gImNociIpICU+JSAKICAgIG11dGF0ZShicF9jdW0gPSBlbmQgKyBzaXplX2N1bSkgJT4lCiAgICB0cmFuc2Zvcm0oYXMubnVtZXJpYyh3ZWlnaHQpKSAlPiUKICAgIG11dGF0ZSh3ZWlnaHQ9IGNvYWxlc2NlKHdlaWdodCwgMCkpICU+JQogICAgbXV0YXRlKGludGVyc2VjdD0gaWZlbHNlKHdlaWdodCA9PSAwLCAibGFzc2kgb3V0bGllcnMiLCAiaW50ZXJzZWN0IG91dGxpZXJzIikpCiAKICAjc2V0IHRoZSBjdXQtb2ZmCiAgZGF0YV9sYXNzaTwtIHJlYWQudGFibGUocGFzdGUwKHBhdGgsIGZpbGVzLCBzcCwgImRhdGFfbGFzc2kiKSwgaGVhZGVyID0gVFJVRSkKICBjdXRfOTUgPC0gc29ydChkYXRhX2xhc3NpJHN0YXRpc3RpYylbcm91bmQobGVuZ3RoKGRhdGFfbGFzc2kkc3RhdGlzdGljKSAqIDAuOTUpXQogIHByaW50KHBhc3RlKHNwLCByb3VuZChsZW5ndGgoZGF0YV9sYXNzaSRzdGF0aXN0aWMpICogMC4wNSksICJ0b3AgNSUgdmFsdWVzIikpCiAgcHJpbnQocGFzdGUoc3AsIGN1dF85NSwgIjUlIGN1dC1vZmYiICkpCgoKcDwtICBnZ3Bsb3QoKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YV9hbGwsIG1hcHBpbmc9YWVzKHggPSBicF9jdW0sIHkgPSBzdGF0aXN0aWMsIGNvbG9yID0gaW50ZXJzZWN0LCBzaGFwZT0gaW50ZXJzZWN0LCBzaXplPSBpbnRlcnNlY3QpKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0gY3V0Xzk1LCBjb2xvcj0icmVkIiwgbGluZXR5cGU9ImRhc2hlZCIpICArICAKICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVsID0gZGF0YV9heGlzJGNociwgYnJlYWtzID0gZGF0YV9heGlzJGNlbnRlcl9jdW0pICsKICAgICAgbGFicyAoeD0iQ2hyb21vc29tZSIsIHk9Is6bIiwgdGl0bGUgPSBhcy5jaGFyYWN0ZXIobmFtZXNbc3BdKSkgKwogICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoOCwgMSkpICsKICAgICAgc2NhbGVfYWxwaGEocmFuZ2UgPSBjKDAuNSwgMSksIGd1aWRlPSAibm9uZSIpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyhhcy5jaGFyYWN0ZXIoY29sb3JzW3NwXSksICIjQzhEM0QzIikpICsKICAgICAgc2NhbGVfc2l6ZV9tYW51YWwodmFsdWVzPWMoMywgMSkpICsKICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiaXRhbGljIiwgc2l6ZT0zMCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpLAogICAgICAgICAgKQoKICBhc3NpZ24ocGFzdGUwKHNwLCAiX3Bsb3QiKSwgcCApCiAgYXNzaWduKHBhc3RlMChzcCwgIl9kYXRhIiksIGRhdGFfYWxsICkKICB9ICAKCgojIyBjdXN0b21pemUKcTwtIGdnYXJyYW5nZShsY19wbG90LCBsbF9wbG90LCBscF9wbG90LCBscl9wbG90LCAKICAgICBuY29sPSAyLCBucm93PSAyLCBjb21tb24ubGVnZW5kPSBUUlVFLCBsZWdlbmQ9ImJvdHRvbSIpIAoKcHJpbnQocSkKCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChwYXRoLCBwbG90cywgIm91dGxpZXJzX3NlbGVjdGlvbi5wbmciKSwgcGxvdD0gcSwgd2lkdGg9IDI1LCBoZWlnaHQgPSAxMCkKYGBgCgpDTEFSSUZJQ0FUSU9OOiBJbiB0aGUgcGxvdCB3ZSBjYW4gc2VlIFwqIGJlbG93IHRoZSBjdXRvZmYuIFRoYXQncyBiZWNhdXNlIGFub3RoZXIgb3ZlcmxhcHBpbmcgd2luZG93IHBhc3NlZCB0aGUgY3V0b2ZmIHZhbHVlLCBzbyBub3cgdGhlIHJlZ2lvbiBpbmNsdWRlcyB3aW5kb3dzIHRoYXQgYnkgaXRzIG93biBkaWRuJ3Qgd2VyZSBvdXRsaWVycy4KCk5vdyBJIHdhbnQgdG8gZXhwbG9yZSByZWdpb25zIGRlZmluZWQgaW4gYSBjaHIKCmBgYHtyICwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTV9CgojIE1ha2UgYSBkaWN0aW9uYXJ5IHRvIGFzc29jaWF0ZSBzcGVjaWVzIHdpdGggdGhlIGRhdGEgZnJhbWVzCmRhdGFfZGljdCA9IGxpc3QoKQogIGRhdGFfZGljdFtbImxjIl1dID0gbGNfZGF0YQogIGRhdGFfZGljdFtbImxsIl1dID0gbGxfZGF0YQogIGRhdGFfZGljdFtbImxwIl1dID0gbHBfZGF0YQogIGRhdGFfZGljdFtbImxyIl1dID0gbHJfZGF0YQoKIyMgTWFrZSBhIGRpY3Rpb25hcnkgdG8gZ2V0IHRoZSBtb3JlIHJlbGV2YW50IGNociBhbmQgYXNzb2NpYXRlIHdpdGggdGhlIHNwZWNpZXMKY2hyX2RpY3QgPSBsaXN0KCkKICAgIGNocl9kaWN0W1sibGMiXV0gPSBjKCAiRDMiLCAiRTEiLCAiQzIiLCAiRjEiLCAiRDQiLCAiQjEiLCAiRTIiKQogICAgY2hyX2RpY3RbWyJsbCJdXSA9IGMoICJCMSIsICJEMyIsICJFMyIsICJBMSIsICJBMyIsICJDMSIsICJCMiIpCiAgICBjaHJfZGljdFtbImxwIl1dID0gYyggIkQzIiwgIkExIiwgIkI0IiwgIkQxIiwgIkEzIiwgIkIxIiwgIkEyIiwgIkIzIiwgIkIyIikKICAgIGNocl9kaWN0W1sibHIiXV0gPSBjKCAiQTEiLCAiQjEiLCAiRDMiLCAiRDIiLCAiRTMiLCAiRDQiLCAiRTEiKQoKZm9yIChzcCBpbiBzcGVjaWVzKQp7CiAgIyBHZXQgdGhlIGRmIGFuZCB0aGUgY2hyIGxpc3QgZm9yIHRoZSBjdXJyZW50IHNwZWNpZXMgaW4gdGhlIGxvb3AKICBkYXRhIDwtIGRhdGFfZGljdFtbc3BdXQogIGNociA8LSAgY2hyX2RpY3RbW3NwXV0gCiAgCiAgIyBMaXN0IG9iamVjdHMgaW4gdGhlIGN1cnJlbnQgZW52aXJvbm1lbnQgbWF0Y2hpbmcgdGhlIHBhdHRlcm4gIipfcGxvdCIKICBwbG90X25hbWVzIDwtIGxzKHBhdHRlcm4gPSAiLl9wbG90JCIpCgogICMgUmVtb3ZlIG9iamVjdHMgd2l0aCBuYW1lcyBtYXRjaGluZyB0aGUgcGF0dGVybiAodGhpcyBpcyBpbXBvcnRhbnQgZm9yIHRoZSBsb29wKQogIHJtKGxpc3QgPSBwbG90X25hbWVzKSAKICAKICBmb3IgKGkgaW4gY2hyKSAKICB7CiAgY2hyX2RhdGE8LSBkYXRhICU+JQogICAgZmlsdGVyKGNociA9PSBpKSAgIAoKICAgICBwPC0gZ2dwbG90KCkgKwogICAgICAgZ2VvbV9wb2ludChjaHJfZGF0YSwgbWFwcGluZz1hZXMoeCA9IGJwX2N1bSwgeSA9IHN0YXRpc3RpYywgCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBpbnRlcnNlY3QsIHNoYXBlPSBpbnRlcnNlY3QsIHNpemU9IGludGVyc2VjdCkpICsKICAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0gY3V0Xzk1LCBjb2xvcj0icmVkIiwgbGluZXR5cGU9ImRhc2hlZCIpICsgIAogICAgICAgeGxhYiAoaSkgKwogICAgICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDgsIDEpKSArCiAgICAgICBzY2FsZV9hbHBoYShyYW5nZSA9IGMoMC41LCAxKSwgZ3VpZGU9ICJub25lIikgKwogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0gYyhhcy5jaGFyYWN0ZXIoY29sb3JzW3NwXSksICIjQ0NEMUQxIikpICsKICAgICAgIHNjYWxlX3NpemVfbWFudWFsKHZhbHVlcz1jKDMsIDEpKSArCiAgICAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9Im5vbmUiLCBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfYmxhbmsoKSkKICAgICAgCiAgICBhc3NpZ24ocGFzdGUwKGksICJfcGxvdCIpLCBwICkKICAgIAogIH0KICAKICAjIyBjdXN0b21pemUgdGhlIHBsb3QKICBwbG90X25hbWVzIDwtIGxzKHBhdHRlcm4gPSAiLl9wbG90JCIpICAKICBwbG90X2xpc3QgPC0gbGFwcGx5KHBsb3RfbmFtZXMsIGdldCkKICBxPC0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGxvdF9saXN0LCB3aWR0aHMgPSBjKDEpKQogIHEgPC0gYW5ub3RhdGVfZmlndXJlKHEsIHRvcCA9IHRleHRfZ3JvYihhcy5jaGFyYWN0ZXIobmFtZXNbc3BdKSwgZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMzApKQogIAogIHByaW50KHEpCn0KCmBgYAoKIyMjIDIuMyBSZXByZXNlbnRhdGlvbiBvZiBYUC1FSEgKCmBgYHtyICwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTV9CgojIFhQLUVISCByZXN1bHRzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KI1JlYWQgdGhlIGRhdGEKIyBMaXN0IGZpbGVzIGluIHRoZSBkaXJlY3RvcnkKZmlsZV9saXN0IDwtIGxpc3QuZmlsZXMocGFzdGUwKHBhdGgsIGZpbGVzKSwgcGF0dGVybiA9ICIueHBlaGhfc2NhbiQiLCBmdWxsLm5hbWVzID0gRkFMU0UpCgojTWFrZSBhIGRpY3Rpb25hcnkgdG8gYXNzb2NpYXRlIGZpbGUgbmFtZXMgd2l0aCBzcGVjaWVzCiMjIyMjIyMjIyMjIyMjIyMjIyNBUVVJIEVTVE9ZISEjIyMjIyMjIyMjIyMjIyMjCnhwZWhoX2RpY3QgPSBsaXN0KCkKICB4cGVoaF9kaWN0W1sibGMiXV0gPSBsY19kYXRhCiAgeHBlaGhfZGljdFtbImxsIl1dID0gbGxfZGF0YQogIHhwZWhoX2RpY3RbWyJscCJdXSA9IGxwX2RhdGEKICB4cGVoaF9kaWN0W1sibHIiXV0gPSBscl9kYXRhCgpmb3IgKGkgaW4gZmlsZV9saXN0KQp7ICAKICBkYXRhIDwtIHJlYWQudGFibGUocGFzdGUwKCBwYXRoLCBmaWxlcywgaSksIHNlcD0iXHQiLCBoZWFkZXI9IFRSVUUsIGNvbC5uYW1lcyA9IGMoImNociIsICJwb3MiLCAieHBlaGgiLCAicHZhbCIpKQogIAogICNHcm91cCBieSBjaHIKICBkYXRhX2N1bSA8LSBkYXRhICU+JSAKICAgIGdyb3VwX2J5KGNocikgJT4lIAogICAgc3VtbWFyaXNlKG1heF9icCA9IG1heChwb3MpKSAlPiUKICAgIG11dGF0ZShicF9hZGQgPSBsYWcoY3Vtc3VtKGFzLm51bWVyaWMobWF4X2JwKSksIGRlZmF1bHQgPSAwKSkgJT4lIAogICAgc2VsZWN0KGNociwgYnBfYWRkKQogIAogIGRhdGFfeHBlaGggPC0gZGF0YSAlPiUgCiAgICBpbm5lcl9qb2luKGRhdGFfY3VtLCBieSA9ICJjaHIiKSAlPiUgCiAgICBtdXRhdGUoYnBfY3VtID0gcG9zICsgYnBfYWRkKSAlPiUKICAgIG5hLm9taXQoKSAlPiUKICAgIHN1YnNldCh4cGVoaCA+IDApICU+JQogICAgbXV0YXRlKHNwPSBpKQogIAogIHA8LSBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvaW50KGRhdGFfeHBlaGgsIG1hcHBpbmc9YWVzKHg9IGJwX2N1bSwgeT1wdmFsLCBhbHBoYSA9IDAuNSwgY29sb3IgPSBhc19mYWN0b3Ioc3ApKSkgKyAKICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWwgPSBkYXRhX2F4aXMkY2hyLCBicmVha3MgPSBkYXRhX2F4aXMkY2VudGVyX2N1bSkgKwogICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0gMiwgY29sb3I9InJlZCIsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICAgbGFicyAoeD0gImNocm9tb3NvbWVzIiwgeT0gInhwLWVoaCBwLXZhbHVlIEZEUiIsIHRpdGxlPSBpKSArCiAgICAgdGhlbWUgKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0ibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiLCBzaXplPSAzMCkpCiAKICBwcmludChwKSAKfSAgICAKIyMjI05PVEE6CiAjIENyZWFyIHVuYSBjb2x1bW5hIGNvbG9yIHBhcmEgY3VhbmRvIHNlIGN1bXBsYW4gbGFzIGNvbmRpY2lvbmVzIGRlIG91dGxpZXIgKyBjb21ibwogIyBQb25lciBiYXJyaXRhcyBwYXJhIGRlbGltaXRhciBsb3MgY3JvbW9zb21hcwogIyBTb2x1Y2lvbmFyIGxhcyBjb21iaW5hY2lvbmVzIGRlICsgeSArCmBgYAoKIyMgMy4gSW50ZXJwcmV0YXRpb24KCiMjIyAzLjEgTG9va2luZyBmb3IgZW5yaWNobWVudCBwYXRod2F5cwoKV2UgdHJpZWQgdG8gZmluZCBvdXQgcGF0aHdheXMgb3IgZnVuY3Rpb25zIHNwZWNpZmljYWxseSBiZWluZyB1bmRlciBzZWxlY3Rpb24gcHJlc3N1cmUgYW1vbmcgdGhlIHB1dGF0aXZlIHNlbGVjdGVkIHJlZ2lvbnMgKHRob3NlIG92ZXJwYXNzaW5nIHRoZSBmaWx0ZXIgZm9yIGJvdGggbWV0aG9kcykuIFVuZm9ydHVuYXRlbHksIEdPIGVucmljaG1lbnQgYW5hbHlzZXMgZG9uZSBpbiBQQU5USEVSIHJlc3VsdHMgaW4gbm8gZW5yaWNobWVudCBwYXRod2F5IGluIG5vIHNwZWNpZXMuCgojIyMgMy4yIFRvcCByZWdpb25zCgpBcyB3ZSBkaWRuJ3QgZ2V0IGFueSBzaWduaWZpY2FudCByZXN1bHQgaW4gdGhlIGVucmljaG1lbnQgYW5hbHlzZXMsIHdlIGRlY2lkZWQgdG8gbG9vayBmb3IgdGhlIG1vc3QgaW1wb3J0YW50IHJlZ2lvbnMgdW5kZXIgc2VsZWN0aW9uIGluIGVhY2ggc3BlY2llcy4gRm9yIGRvaW5nIHNvLCB3ZSBoYWQgdG8gZGVjaWRlZCB3aGF0IHBhcmFtZXRlciBkZXNjcmliZXMgYmV0dGVyIHdoaWNoIHJlZ2lvbnMgYXJlICJ0aGUgbW9zdCBpbXBvcnRhbnQgb25lcyIuCgpGcm9tIHRoZSByZXN1bHRpbmcgdGFibGUgSSBnZXQgdGhlIHRvcCAxMCBwdXRhdGl2ZSByZWdpb25zIHBlciBzcC4KCmBgYHtyfQojUmVhZCBkYXRhCmZvciAoc3AgaW4gc3BlY2llcykKewpkYXRhPC0gcmVhZC50YWJsZShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiX2xhc3NpX2loc19yZWdpb25zIiksIHNlcD0iXHQiLCBoZWFkZXI9VCkKYXNzaWduKHBhc3RlMChzcCwgIl9yZXN1bHRzIiksIGRhdGEgKQoKZGF0YV90b3AxMDwtIGRhdGEgJT4lCiAgYXJyYW5nZShkZXNjKGxhc3NpX21heCkpICU+JQogIHNsaWNlKDE6MTApCiN3cml0ZS50YWJsZShkYXRhX3RvcDEwLCBmaWxlPShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiX3RvcDEwIikpLCBzZXA9Ilx0Iixyb3cubmFtZXMgPSBGQUxTRSwgcXVvdGUgPSBGQUxTRSkKCmFzc2lnbihwYXN0ZTAoc3AsICJfdG9wMTAiKSwgZGF0YV90b3AxMCApCn0KCmBgYAoKSW4gb3JkZXIgdG8gZXhwbG9yZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBsYXNzaSBzdGF0aXN0aWMgaW4gZWFjaCBvZiB0aGUgMTAgdG9wIHJlZ2lvbnMsIEkgZmlyc3RseSBnZXQgdGhlIHN0YXRpc3RpYyB2YWx1ZSBpbiBldmVyeSB3aW5kb3cgb2YgdGhlIHRvcCByZWdpb24gYW5kIHRoZW4gcmVwcmVzZW50IGl0LgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KbW9kdWxlIGxvYWQgYmVkdG9vbHMKCnNwZWNpZXM9KGxjIGxsIGxwIGxyKQoKZm9yIHNwIGluICR7c3BlY2llc1tAXX0KICBkbwogICAgZWNobyAiJHNwIgogICAgI2NvbnZlcnQgaW50byBhIGJlZCBmaWxlCiAgICBhd2sgJ3twcmludGYoIiVzXHQlZFx0JWRcdCVkXHQlZFxuIiwgJDEsICQyLCAkMywgJDUsICQxMil9JyBzYWx0aUxBU1NJLyR7c3B9X3NhbHRpLmxhc3NpcC5oYXAub3V0ICA+ICR7c3B9X3RtcAoKICAgICNpbnRlcnNlY3QgYnR3IGxhc3NpIHZhbHVlcyBhbmQgZ2Vub21pYyByZWdpb25zIHdpdGggMTAwJSBjb2luY2lkZW5jZSAob25seSB3aW5kb3dzIGVtYmVkZGVkIGluIHRoZSBnZW5vbWljIHJlZ2lvbnMgYXJlIHJlcG9ydGVkKQogICAgICAgYmVkdG9vbHMgaW50ZXJzZWN0IC13YSAtd2IgXAogICAgICAgLWEgPChncmVwIC12ICJjaHIiICR7c3B9X3RtcCkgXAogICAgICAgLWIgPChncmVwIC12ICJjaHIiICR7c3B9X3RvcDEwIHwgY3V0IC1mMS0zKSBcCiAgICAgICAtZiAxLjAgXAogICAgICAgPiAke3NwfV9sYXNzaV90b3AxMCAgCiAgICAgICBlY2hvICIkc3AgaW50ZXJzZWN0ZWQiCiAgICAKICAjcmVtb3ZlIHRlbXBvcmFsIGZpbGVzCiAgcm0gKnRtcAogIGRvbmUKCmBgYAoKTm93IEkgd2FudCB0byByZXByZXNlbnQgZWFjaCB0b3AxMCBnZW5vbWljIHJlZ2lvbnMgYW5kIHRoZSBjb3JyZXNwb25kZW50IGxhc3NpIHZhbHVlcy4gVGFraW5nIGludG8gYWNjb3VudCBJIHByZXZpb3VzbHkgY2FsY3VsYXRlZCB0aGUgZ2VuZXMgdW5kZXIgdGhlIGdlbm9taWMgb3V0bGllciByZWdpb25zLCB3ZSBjYW4gYWRkIHRoaXMgaW5mbyB0byB0aGUgcGxvdAoKYGBge3IgLCBlY2hvID0gRkFMU0UsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTV9CiAgI1JlYWQgZGF0YQpmb3IgKHNwIGluIHNwZWNpZXMpCnsKbGFzc2k8LSByZWFkLnRhYmxlKHBhc3RlMChwYXRoLCBmaWxlcywgc3AsICJfbGFzc2lfdG9wMTAiKSwgc2VwPSJcdCIsIGhlYWRlcj1GLCBjb2wubmFtZXMgPSBjKCJjaHIiLCAid19zdGFydCIsICJ3X2VuZCIsICJwb3MiLCAibGFzc2kiLCAiY2hyX3IiLCAic3RhcnQiLCAiZW5kIikpCgpnZW5lczwtIHJlYWQudGFibGUocGFzdGUwKHBhdGgsIGZpbGVzLCBzcCwgIl9nZW5vbWljX3JlZ2lvbnNfYW5ub3RhdGVkIiksIHNlcD0iICIsIGhlYWRlcj1UKQoKZGF0YSA8LSBsZWZ0X2pvaW4obGFzc2ksIGdlbmVzLCBieT0gInN0YXJ0IikgJT4lCiAgc2VsZWN0IChjaHIueCwgd19zdGFydCwgd19lbmQsIHBvcywgbGFzc2ksIHN0YXJ0LCBlbmQueCwgZ2VuZV9zdGFydCwgZ2VuZV9lbmQsIGVuc2VtYmxfaWQsIGdlbmVfbmFtZSApCgphbm5vdGF0aW9uICA8LSBkYXRhICU+JSBzZWxlY3QoY2hyLngsIHN0YXJ0LCBlbmQueCwgZ2VuZV9zdGFydCwgZ2VuZV9lbmQsIGdlbmVfbmFtZSkgJT4lIGRpc3RpbmN0KCkgJT4lIG5hLm9taXQoKQogCmFzc2lnbihwYXN0ZTAoc3AsICJfZGF0YSIpLCBkYXRhICkKYXNzaWduKHBhc3RlMChzcCwgIl9hbm5vdGF0aW9uIiksIGFubm90YXRpb24gKQoKcmVnaW9ucyA8LSB1bmlxdWUoZGF0YSRzdGFydCkKCiMgTGlzdCBvYmplY3RzIGluIHRoZSBjdXJyZW50IGVudmlyb25tZW50IG1hdGNoaW5nIHRoZSBwYXR0ZXJuICIqX3Bsb3QiCiAgcGxvdF9uYW1lcyA8LSBscyhwYXR0ZXJuID0gIi5fcGxvdCQiKQoKICAjIFJlbW92ZSBvYmplY3RzIHdpdGggbmFtZXMgbWF0Y2hpbmcgdGhlIHBhdHRlcm4gKHRoaXMgaXMgaW1wb3J0YW50IGZvciB0aGUgbG9vcCkKICBybShsaXN0ID0gcGxvdF9uYW1lcykgCiAgCiAgZm9yIChpIGluICgxOmxlbmd0aChyZWdpb25zKSkpCiAgewogIGQgPC0gZGF0YSAlPiUgZmlsdGVyKHN0YXJ0ID09IHJlZ2lvbnNbaV0pIAogIGMgPC0gdW5pcXVlKGQkY2hyKQogIAogIHA8LSBnZ3Bsb3QoZCwgbWFwcGluZz1hZXMoeCA9IHBvcywgeSA9IGxhc3NpKSkgKwogICAgZ2VvbV9saW5lKGNvbG9yPSBhcy5jaGFyYWN0ZXIoY29sb3JzW3NwXSksIHNpemU9IDEpICsKICAgIGdlb21fcG9pbnQoY29sb3I9IGFzLmNoYXJhY3Rlcihjb2xvcnNbc3BdKSwgc2l6ZT0gMykgKwogICAgZ2VvbV9zZWdtZW50KG1hcHBpbmc9IGFlcyh4ID0gZ2VuZV9zdGFydCwgeGVuZD0gZ2VuZV9lbmQsIHk9IChtYXgobGFzc2kpICsgMTApICwgeWVuZCA9IChtYXgobGFzc2kpICsgMTApKSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiI0NDRDFEMSIsIGxpbmV3aWR0aCA9IDEwKSArCiAgICB4bGFiIChjKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguOTAsIC41MCkpIAoKICBhc3NpZ24ocGFzdGUwKGksICJfcmVnaW9uX3Bsb3QiKSwgcCApCiAgICAKICB9CiAgCiAgIyMgY3VzdG9taXplIHRoZSBwbG90CiAgcGxvdF9uYW1lcyA8LSBscyhwYXR0ZXJuID0gIi5yZWdpb25fcGxvdCQiKSAgCiAgcGxvdF9saXN0IDwtIGxhcHBseShwbG90X25hbWVzLCBnZXQpCiAgcyA8LSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBwbG90X2xpc3QpCiAgcyA8LSBhbm5vdGF0ZV9maWd1cmUocywgdG9wID0gdGV4dF9ncm9iKGFzLmNoYXJhY3RlcihuYW1lc1tzcF0pLCBmYWNlID0gIml0YWxpYyIsIHNpemUgPSAzMCkpCiAgCiAgcHJpbnQocykKfQpgYGAKCmBgYHtyICwgZWNobyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDE1fQoKZm9yIChzcCBpbiBzcGVjaWVzKQp7CkQzX2RhdGEgPC0gcmVhZC50YWJsZShwYXN0ZTAocGF0aCxmaWxlcywgc3AsICJfcmVzdWx0c190YWJsZV9yZXByZXNlbnRhdGlvbiIpLCAKICAgICAgICAgICAgICAgICAgICAgIHNlcD0iXHQiLCBoZWFkZXI9IEZBTFNFLCBuYS5zdHJpbmdzID0gIi4iLCAKICAgICAgICAgICAgICAgICAgICAgIGNvbC5uYW1lcyA9IGMoImNociIsICJzdGFydCIsICJlbmQiLCAicG9zIiwgInN0YXRpc3RpYyIsICJyX2NociIsICJyX3N0YXJ0IiwgInJfZW5kIiwgIm5fd2luZG93cyIsICJuX3NucHMiLCAid2VpZ2h0ZWRfc3RhdGlzdGljIiwgIndpbmRvd19zaXplIiwgIndlaWdodCIsICJicF9vdmVybGFwIikpICU+JQogICAgICAgICAgICBmaWx0ZXIoY2hyID09ICJEMyIpIAoKRDNfYW5ub3RhdHRpb24gPC0gcmVhZC50YWJsZShwYXN0ZTAocGF0aCwgZmlsZXMsIHNwLCAiX2dlbm9taWNfcmVnaW9uc19hbm5vdGF0ZWQiKSwgc2VwPSIgIiwgaGVhZGVyPVQpICU+JQogICAgICAgICAgICBmaWx0ZXIoY2hyID09ICJEMyIpICU+JQogICAgICAgICAgICBkaXN0aW5jdCgpICU+JSBuYS5vbWl0KCkKICAKCmFzc2lnbihwYXN0ZTAoc3AsICJfRDNfZGF0YSIpLCBEM19kYXRhKQphc3NpZ24ocGFzdGUwKHNwLCAiX0QzX2Fubm90YXR0aW9uIiksIEQzX2Fubm90YXR0aW9uKQp9CgpvcHRpb25zKGdncmVwZWwubWF4Lm92ZXJsYXBzID0gSW5mKQoKcDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUobGNfRDNfZGF0YSwgbWFwcGluZz1hZXMoeCA9IHBvcywgeSA9IHN0YXRpc3RpYyksIGNvbG9yPSBhcy5jaGFyYWN0ZXIoY29sb3JzWyJsYyJdKSwgc2l6ZT0gMS41LCBhbHBoYT0gMC44KSArCiAgZ2VvbV9saW5lKGxsX0QzX2RhdGEsIG1hcHBpbmc9YWVzKHggPSBwb3MsIHkgPSBzdGF0aXN0aWMpLCBjb2xvcj0gYXMuY2hhcmFjdGVyKGNvbG9yc1sibGwiXSksIHNpemU9IDEuNSwgYWxwaGE9IDAuOCkgKwogIGdlb21fbGluZShscF9EM19kYXRhLCBtYXBwaW5nPWFlcyh4ID0gcG9zLCB5ID0gc3RhdGlzdGljKSwgY29sb3I9IGFzLmNoYXJhY3Rlcihjb2xvcnNbImxwIl0pLCBzaXplPSAxLjUsIGFscGhhPSAwLjgpICsKICBnZW9tX2xpbmUobHJfRDNfZGF0YSwgbWFwcGluZz1hZXMoeCA9IHBvcywgeSA9IHN0YXRpc3RpYyksIGNvbG9yPSBhcy5jaGFyYWN0ZXIoY29sb3JzWyJsciJdKSwgc2l6ZT0gMS41LCBhbHBoYT0gMC44KSArCiAgZ2VvbV9sYWJlbF9yZXBlbChsY19EM19hbm5vdGF0dGlvbiwgbWFwcGluZyA9YWVzKHg9IHN0YXJ0LCB5PSAobGFzc2lfbWF4KSwgbGFiZWw9IGdlbmVfbmFtZSksIGNvbG9yPSBhcy5jaGFyYWN0ZXIoY29sb3JzWyJsYyJdKSwgc2l6ZT0gNSwgc2hvdy5sZWdlbmQgPSBUUlVFKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChsbF9EM19hbm5vdGF0dGlvbiwgbWFwcGluZyA9YWVzKHg9IHN0YXJ0LCB5PSAobGFzc2lfbWF4KSwgbGFiZWw9IGdlbmVfbmFtZSksIGNvbG9yPSBhcy5jaGFyYWN0ZXIoY29sb3JzWyJsbCJdKSwgc2l6ZT0gNSkgKwogIGdlb21fbGFiZWxfcmVwZWwobHBfRDNfYW5ub3RhdHRpb24sIG1hcHBpbmcgPWFlcyh4PSBzdGFydCwgeT0gKGxhc3NpX21heCksIGxhYmVsPSBnZW5lX25hbWUpLCBjb2xvcj0gYXMuY2hhcmFjdGVyKGNvbG9yc1sibHAiXSksIHNpemU9IDUpICsKICBnZW9tX2xhYmVsX3JlcGVsKGxyX0QzX2Fubm90YXR0aW9uLCBtYXBwaW5nID1hZXMoeD0gc3RhcnQsIHk9IChsYXNzaV9tYXgpLCBsYWJlbD0gZ2VuZV9uYW1lKSwgY29sb3I9IGFzLmNoYXJhY3Rlcihjb2xvcnNbImxyIl0pLCBzaXplPSA1KSArCiAgCiAgbGFicyAodGl0bGU9ICJTZWxlY3Rpb24gYW5hbHlzZXMgaW4gQ2hyb21vc29tZSBEMyIsIHg9ICJQb3NpdGlvbiBpbiBicCIsIHk9ICLOmyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNSxmYWNlPSJib2xkIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTI1LCBoanVzdD0gMC41LCB2anVzdCA9IDMpLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMSwxLDEpLCAiY20iKSkKCnByaW50KHApIApnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAocGF0aCwgcGxvdHMsICJEM19zZWxlY3Rpb24ucG5nIiksIHBsb3Q9IHAsIHdpZHRoPSAxNSwgaGVpZ2h0ID0gMTApCmBgYAo=